video_core: Use interval map for cached_pages

* Also eliminate g_memory in hardware renderers
This commit is contained in:
GPUCode
2023-02-04 12:57:57 +02:00
parent 938ec204f5
commit fd9525acc2
12 changed files with 161 additions and 155 deletions

View File

@@ -88,98 +88,6 @@ void RasterizerAccelerated::AddTriangle(const Pica::Shader::OutputVertex& v0,
vertex_batch.emplace_back(v2, AreQuaternionsOpposite(v0.quat, v2.quat)); vertex_batch.emplace_back(v2, AreQuaternionsOpposite(v0.quat, v2.quat));
} }
void RasterizerAccelerated::UpdatePagesCachedCount(PAddr addr, u32 size, int delta) {
const u32 page_start = addr >> Memory::CITRA_PAGE_BITS;
const u32 page_end = ((addr + size - 1) >> Memory::CITRA_PAGE_BITS) + 1;
u32 uncache_start_addr = 0;
u32 cache_start_addr = 0;
u32 uncache_bytes = 0;
u32 cache_bytes = 0;
for (u32 page = page_start; page != page_end; page++) {
auto& count = cached_pages.at(page);
// Ensure no overflow happens
if (delta > 0) {
ASSERT_MSG(count < std::numeric_limits<u16>::max(), "Count will overflow!");
} else if (delta < 0) {
ASSERT_MSG(count > 0, "Count will underflow!");
} else {
ASSERT_MSG(false, "Delta must be non-zero!");
}
// Adds or subtracts 1, as count is a unsigned 8-bit value
count += delta;
// Assume delta is either -1 or 1
if (count == 0) {
if (uncache_bytes == 0) {
uncache_start_addr = page << Memory::CITRA_PAGE_BITS;
}
uncache_bytes += Memory::CITRA_PAGE_SIZE;
} else if (uncache_bytes > 0) {
VideoCore::g_memory->RasterizerMarkRegionCached(uncache_start_addr, uncache_bytes,
false);
uncache_bytes = 0;
}
if (count == 1 && delta > 0) {
if (cache_bytes == 0) {
cache_start_addr = page << Memory::CITRA_PAGE_BITS;
}
cache_bytes += Memory::CITRA_PAGE_SIZE;
} else if (cache_bytes > 0) {
VideoCore::g_memory->RasterizerMarkRegionCached(cache_start_addr, cache_bytes, true);
cache_bytes = 0;
}
}
if (uncache_bytes > 0) {
VideoCore::g_memory->RasterizerMarkRegionCached(uncache_start_addr, uncache_bytes, false);
}
if (cache_bytes > 0) {
VideoCore::g_memory->RasterizerMarkRegionCached(cache_start_addr, cache_bytes, true);
}
}
void RasterizerAccelerated::ClearAll(bool flush) {
// Force flush all surfaces from the cache
if (flush) {
FlushRegion(0x0, 0xFFFFFFFF);
}
u32 uncache_start_addr = 0;
u32 uncache_bytes = 0;
for (u32 page = 0; page != cached_pages.size(); page++) {
auto& count = cached_pages.at(page);
// Assume delta is either -1 or 1
if (count != 0) {
if (uncache_bytes == 0) {
uncache_start_addr = page << Memory::CITRA_PAGE_BITS;
}
uncache_bytes += Memory::CITRA_PAGE_SIZE;
} else if (uncache_bytes > 0) {
VideoCore::g_memory->RasterizerMarkRegionCached(uncache_start_addr, uncache_bytes,
false);
uncache_bytes = 0;
}
}
if (uncache_bytes > 0) {
VideoCore::g_memory->RasterizerMarkRegionCached(uncache_start_addr, uncache_bytes, false);
}
cached_pages = {};
}
RasterizerAccelerated::VertexArrayInfo RasterizerAccelerated::AnalyzeVertexArray( RasterizerAccelerated::VertexArrayInfo RasterizerAccelerated::AnalyzeVertexArray(
bool is_indexed, u32 stride_alignment) { bool is_indexed, u32 stride_alignment) {
const auto& regs = Pica::g_state.regs; const auto& regs = Pica::g_state.regs;

View File

@@ -18,18 +18,13 @@ public:
void AddTriangle(const Pica::Shader::OutputVertex& v0, const Pica::Shader::OutputVertex& v1, void AddTriangle(const Pica::Shader::OutputVertex& v0, const Pica::Shader::OutputVertex& v1,
const Pica::Shader::OutputVertex& v2) override; const Pica::Shader::OutputVertex& v2) override;
void UpdatePagesCachedCount(PAddr addr, u32 size, int delta) override;
void NotifyPicaRegisterChanged(u32 id) override; void NotifyPicaRegisterChanged(u32 id) override;
void ClearAll(bool flush) override;
/// Syncs entire status to match PICA registers
void SyncEntireState() override; void SyncEntireState() override;
protected:
/// Sync fixed-function pipeline state /// Sync fixed-function pipeline state
virtual void SyncFixedState() = 0; virtual void SyncFixedState() = 0;
protected:
/// Notifies that a fixed function PICA register changed to the video backend /// Notifies that a fixed function PICA register changed to the video backend
virtual void NotifyFixedFunctionPicaRegisterChanged(u32 id) = 0; virtual void NotifyFixedFunctionPicaRegisterChanged(u32 id) = 0;
@@ -137,7 +132,6 @@ protected:
VertexArrayInfo AnalyzeVertexArray(bool is_indexed, u32 stride_alignment = 1); VertexArrayInfo AnalyzeVertexArray(bool is_indexed, u32 stride_alignment = 1);
protected: protected:
std::array<u16, 0x30000> cached_pages{};
std::vector<HardwareVertex> vertex_batch; std::vector<HardwareVertex> vertex_batch;
bool shader_dirty = true; bool shader_dirty = true;

View File

@@ -12,8 +12,8 @@
#include "common/alignment.h" #include "common/alignment.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/microprofile.h" #include "common/microprofile.h"
#include "core/memory.h"
#include "video_core/pica_state.h" #include "video_core/pica_state.h"
#include "video_core/rasterizer_accelerated.h"
#include "video_core/rasterizer_cache/surface_base.h" #include "video_core/rasterizer_cache/surface_base.h"
#include "video_core/rasterizer_cache/surface_params.h" #include "video_core/rasterizer_cache/surface_params.h"
#include "video_core/rasterizer_cache/utils.h" #include "video_core/rasterizer_cache/utils.h"
@@ -22,7 +22,7 @@
namespace VideoCore { namespace VideoCore {
inline auto RangeFromInterval(auto& map, SurfaceInterval interval) { inline auto RangeFromInterval(auto& map, const auto& interval) {
return boost::make_iterator_range(map.equal_range(interval)); return boost::make_iterator_range(map.equal_range(interval));
} }
@@ -70,9 +70,10 @@ private:
using SurfaceRect_Tuple = std::tuple<Surface, Common::Rectangle<u32>>; using SurfaceRect_Tuple = std::tuple<Surface, Common::Rectangle<u32>>;
using SurfaceSurfaceRect_Tuple = std::tuple<Surface, Surface, Common::Rectangle<u32>>; using SurfaceSurfaceRect_Tuple = std::tuple<Surface, Surface, Common::Rectangle<u32>>;
using PageMap = boost::icl::interval_map<u32, int>;
public: public:
RasterizerCache(VideoCore::RasterizerAccelerated& rasterizer, TextureRuntime& runtime); RasterizerCache(Memory::MemorySystem& memory, TextureRuntime& runtime);
~RasterizerCache() = default; ~RasterizerCache() = default;
/// Get the best surface match (and its match type) for the given flags /// Get the best surface match (and its match type) for the given flags
@@ -124,6 +125,9 @@ public:
/// Flush all cached resources tracked by this cache manager /// Flush all cached resources tracked by this cache manager
void FlushAll(); void FlushAll();
/// Clear all cached resources tracked by this cache manager
void ClearAll(bool flush);
private: private:
void DuplicateSurface(const Surface& src_surface, const Surface& dest_surface); void DuplicateSurface(const Surface& src_surface, const Surface& dest_surface);
@@ -159,23 +163,24 @@ private:
/// Remove surface from the cache /// Remove surface from the cache
void UnregisterSurface(const Surface& surface); void UnregisterSurface(const Surface& surface);
/// Increase/decrease the number of surface in pages touching the specified region
void UpdatePagesCachedCount(PAddr addr, u32 size, int delta);
private: private:
VideoCore::RasterizerAccelerated& rasterizer; Memory::MemorySystem& memory;
TextureRuntime& runtime; TextureRuntime& runtime;
SurfaceCache surface_cache; SurfaceCache surface_cache;
PageMap cached_pages;
SurfaceMap dirty_regions; SurfaceMap dirty_regions;
SurfaceSet remove_surfaces; SurfaceSet remove_surfaces;
u16 resolution_scale_factor; u16 resolution_scale_factor;
std::vector<std::function<void()>> download_queue; std::vector<std::function<void()>> download_queue;
std::vector<u8> staging_buffer;
std::unordered_map<TextureCubeConfig, Surface> texture_cube_cache; std::unordered_map<TextureCubeConfig, Surface> texture_cube_cache;
std::recursive_mutex mutex;
}; };
template <class T> template <class T>
RasterizerCache<T>::RasterizerCache(VideoCore::RasterizerAccelerated& rasterizer, RasterizerCache<T>::RasterizerCache(Memory::MemorySystem& memory_, TextureRuntime& runtime_)
TextureRuntime& runtime) : memory{memory_}, runtime{runtime_} {
: rasterizer{rasterizer}, runtime{runtime} {
resolution_scale_factor = VideoCore::GetResolutionScaleFactor(); resolution_scale_factor = VideoCore::GetResolutionScaleFactor();
} }
@@ -910,7 +915,7 @@ void RasterizerCache<T>::UploadSurface(const Surface& surface, SurfaceInterval i
const auto staging = runtime.FindStaging( const auto staging = runtime.FindStaging(
load_info.width * load_info.height * surface->GetInternalBytesPerPixel(), true); load_info.width * load_info.height * surface->GetInternalBytesPerPixel(), true);
MemoryRef source_ptr = VideoCore::g_memory->GetPhysicalRef(load_info.addr); MemoryRef source_ptr = memory.GetPhysicalRef(load_info.addr);
if (!source_ptr) [[unlikely]] { if (!source_ptr) [[unlikely]] {
return; return;
} }
@@ -944,7 +949,7 @@ void RasterizerCache<T>::DownloadSurface(const Surface& surface, SurfaceInterval
surface->Download(download, staging); surface->Download(download, staging);
MemoryRef dest_ptr = VideoCore::g_memory->GetPhysicalRef(flush_start); MemoryRef dest_ptr = memory.GetPhysicalRef(flush_start);
if (!dest_ptr) [[unlikely]] { if (!dest_ptr) [[unlikely]] {
return; return;
} }
@@ -964,7 +969,7 @@ void RasterizerCache<T>::DownloadFillSurface(const Surface& surface, SurfaceInte
const u32 flush_end = boost::icl::last_next(interval); const u32 flush_end = boost::icl::last_next(interval);
ASSERT(flush_start >= surface->addr && flush_end <= surface->end); ASSERT(flush_start >= surface->addr && flush_end <= surface->end);
MemoryRef dest_ptr = VideoCore::g_memory->GetPhysicalRef(flush_start); MemoryRef dest_ptr = memory.GetPhysicalRef(flush_start);
if (!dest_ptr) [[unlikely]] { if (!dest_ptr) [[unlikely]] {
return; return;
} }
@@ -1062,9 +1067,32 @@ bool RasterizerCache<T>::ValidateByReinterpretation(const Surface& surface, Surf
} }
template <class T> template <class T>
void RasterizerCache<T>::FlushRegion(PAddr addr, u32 size, Surface flush_surface) { void RasterizerCache<T>::ClearAll(bool flush) {
std::lock_guard lock{mutex}; const auto flush_interval = PageMap::interval_type::right_open(0x0, 0xFFFFFFFF);
// Force flush all surfaces from the cache
if (flush) {
FlushRegion(0x0, 0xFFFFFFFF);
}
// Unmark all of the marked pages
for (auto& pair : RangeFromInterval(cached_pages, flush_interval)) {
const auto interval = pair.first & flush_interval;
const PAddr interval_start_addr = boost::icl::first(interval) << Memory::CITRA_PAGE_BITS;
const PAddr interval_end_addr = boost::icl::last_next(interval) << Memory::CITRA_PAGE_BITS;
const u32 interval_size = interval_end_addr - interval_start_addr;
memory.RasterizerMarkRegionCached(interval_start_addr, interval_size, false);
}
// Remove the whole cache without really looking at it.
cached_pages -= flush_interval;
dirty_regions -= SurfaceInterval(0x0, 0xFFFFFFFF);
surface_cache -= SurfaceInterval(0x0, 0xFFFFFFFF);
remove_surfaces.clear();
}
template <class T>
void RasterizerCache<T>::FlushRegion(PAddr addr, u32 size, Surface flush_surface) {
if (size == 0) [[unlikely]] { if (size == 0) [[unlikely]] {
return; return;
} }
@@ -1116,8 +1144,6 @@ void RasterizerCache<T>::FlushAll() {
template <class T> template <class T>
void RasterizerCache<T>::InvalidateRegion(PAddr addr, u32 size, const Surface& region_owner) { void RasterizerCache<T>::InvalidateRegion(PAddr addr, u32 size, const Surface& region_owner) {
std::lock_guard lock{mutex};
if (size == 0) [[unlikely]] { if (size == 0) [[unlikely]] {
return; return;
} }
@@ -1189,28 +1215,60 @@ auto RasterizerCache<T>::CreateSurface(SurfaceParams& params) -> Surface {
template <class T> template <class T>
void RasterizerCache<T>::RegisterSurface(const Surface& surface) { void RasterizerCache<T>::RegisterSurface(const Surface& surface) {
std::lock_guard lock{mutex};
if (surface->registered) { if (surface->registered) {
return; return;
} }
surface->registered = true; surface->registered = true;
surface_cache.add({surface->GetInterval(), SurfaceSet{surface}}); surface_cache.add({surface->GetInterval(), SurfaceSet{surface}});
rasterizer.UpdatePagesCachedCount(surface->addr, surface->size, 1); UpdatePagesCachedCount(surface->addr, surface->size, 1);
} }
template <class T> template <class T>
void RasterizerCache<T>::UnregisterSurface(const Surface& surface) { void RasterizerCache<T>::UnregisterSurface(const Surface& surface) {
std::lock_guard lock{mutex};
if (!surface->registered) { if (!surface->registered) {
return; return;
} }
surface->registered = false; surface->registered = false;
rasterizer.UpdatePagesCachedCount(surface->addr, surface->size, -1); UpdatePagesCachedCount(surface->addr, surface->size, -1);
surface_cache.subtract({surface->GetInterval(), SurfaceSet{surface}}); surface_cache.subtract({surface->GetInterval(), SurfaceSet{surface}});
} }
template <class T>
void RasterizerCache<T>::UpdatePagesCachedCount(PAddr addr, u32 size, int delta) {
const u32 num_pages =
((addr + size - 1) >> Memory::CITRA_PAGE_BITS) - (addr >> Memory::CITRA_PAGE_BITS) + 1;
const u32 page_start = addr >> Memory::CITRA_PAGE_BITS;
const u32 page_end = page_start + num_pages;
// Interval maps will erase segments if count reaches 0, so if delta is negative we have to
// subtract after iterating
const auto pages_interval = PageMap::interval_type::right_open(page_start, page_end);
if (delta > 0) {
cached_pages.add({pages_interval, delta});
}
for (const auto& pair : RangeFromInterval(cached_pages, pages_interval)) {
const auto interval = pair.first & pages_interval;
const int count = pair.second;
const PAddr interval_start_addr = boost::icl::first(interval) << Memory::CITRA_PAGE_BITS;
const PAddr interval_end_addr = boost::icl::last_next(interval) << Memory::CITRA_PAGE_BITS;
const u32 interval_size = interval_end_addr - interval_start_addr;
if (delta > 0 && count == delta) {
memory.RasterizerMarkRegionCached(interval_start_addr, interval_size, true);
} else if (delta < 0 && count == -delta) {
memory.RasterizerMarkRegionCached(interval_start_addr, interval_size, false);
} else {
ASSERT(count >= 0);
}
}
if (delta < 0) {
cached_pages.add({pages_interval, delta});
}
}
} // namespace VideoCore } // namespace VideoCore

View File

@@ -13,7 +13,6 @@
#include "video_core/renderer_opengl/gl_driver.h" #include "video_core/renderer_opengl/gl_driver.h"
#include "video_core/renderer_opengl/gl_rasterizer.h" #include "video_core/renderer_opengl/gl_rasterizer.h"
#include "video_core/renderer_opengl/gl_shader_gen.h" #include "video_core/renderer_opengl/gl_shader_gen.h"
#include "video_core/renderer_opengl/gl_vars.h"
#include "video_core/renderer_opengl/pica_to_gl.h" #include "video_core/renderer_opengl/pica_to_gl.h"
#include "video_core/renderer_opengl/renderer_opengl.h" #include "video_core/renderer_opengl/renderer_opengl.h"
#include "video_core/video_core.h" #include "video_core/video_core.h"
@@ -25,8 +24,9 @@ constexpr std::size_t INDEX_BUFFER_SIZE = 1 * 1024 * 1024;
constexpr std::size_t UNIFORM_BUFFER_SIZE = 2 * 1024 * 1024; constexpr std::size_t UNIFORM_BUFFER_SIZE = 2 * 1024 * 1024;
constexpr std::size_t TEXTURE_BUFFER_SIZE = 1 * 1024 * 1024; constexpr std::size_t TEXTURE_BUFFER_SIZE = 1 * 1024 * 1024;
RasterizerOpenGL::RasterizerOpenGL(Frontend::EmuWindow& emu_window, Driver& driver) RasterizerOpenGL::RasterizerOpenGL(Memory::MemorySystem& memory_, Frontend::EmuWindow& emu_window,
: driver{driver}, runtime{driver}, res_cache{*this, runtime}, Driver& driver_)
: memory{memory_}, driver{driver_}, runtime{driver}, res_cache{memory, runtime},
shader_program_manager{emu_window, driver, !driver.IsOpenGLES()}, shader_program_manager{emu_window, driver, !driver.IsOpenGLES()},
vertex_buffer{GL_ARRAY_BUFFER, VERTEX_BUFFER_SIZE}, uniform_buffer{GL_UNIFORM_BUFFER, vertex_buffer{GL_ARRAY_BUFFER, VERTEX_BUFFER_SIZE}, uniform_buffer{GL_UNIFORM_BUFFER,
UNIFORM_BUFFER_SIZE}, UNIFORM_BUFFER_SIZE},
@@ -210,7 +210,7 @@ void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset,
u32 data_size = loader.byte_count * vertex_num; u32 data_size = loader.byte_count * vertex_num;
res_cache.FlushRegion(data_addr, data_size, nullptr); res_cache.FlushRegion(data_addr, data_size, nullptr);
std::memcpy(array_ptr, VideoCore::g_memory->GetPhysicalPointer(data_addr), data_size); std::memcpy(array_ptr, memory.GetPhysicalPointer(data_addr), data_size);
array_ptr += data_size; array_ptr += data_size;
buffer_offset += data_size; buffer_offset += data_size;
@@ -326,8 +326,8 @@ bool RasterizerOpenGL::AccelerateDrawBatchInternal(bool is_indexed) {
return false; return false;
} }
const u8* index_data = VideoCore::g_memory->GetPhysicalPointer( const u8* index_data =
regs.pipeline.vertex_attributes.GetPhysicalBaseAddress() + memory.GetPhysicalPointer(regs.pipeline.vertex_attributes.GetPhysicalBaseAddress() +
regs.pipeline.index_array.offset); regs.pipeline.index_array.offset);
std::tie(buffer_ptr, buffer_offset, std::ignore) = index_buffer.Map(index_buffer_size, 4); std::tie(buffer_ptr, buffer_offset, std::ignore) = index_buffer.Map(index_buffer_size, 4);
std::memcpy(buffer_ptr, index_data, index_buffer_size); std::memcpy(buffer_ptr, index_data, index_buffer_size);
@@ -772,6 +772,10 @@ void RasterizerOpenGL::FlushAndInvalidateRegion(PAddr addr, u32 size) {
res_cache.InvalidateRegion(addr, size, nullptr); res_cache.InvalidateRegion(addr, size, nullptr);
} }
void RasterizerOpenGL::ClearAll(bool flush) {
res_cache.ClearAll(flush);
}
MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(100, 100, 255)); MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(100, 100, 255));
bool RasterizerOpenGL::AccelerateDisplayTransfer(const GPU::Regs::DisplayTransferConfig& config) { bool RasterizerOpenGL::AccelerateDisplayTransfer(const GPU::Regs::DisplayTransferConfig& config) {
MICROPROFILE_SCOPE(OpenGL_Blits); MICROPROFILE_SCOPE(OpenGL_Blits);

View File

@@ -11,6 +11,10 @@
#include "video_core/renderer_opengl/gl_stream_buffer.h" #include "video_core/renderer_opengl/gl_stream_buffer.h"
#include "video_core/renderer_opengl/gl_texture_runtime.h" #include "video_core/renderer_opengl/gl_texture_runtime.h"
namespace Memory {
class MemorySystem;
}
namespace Frontend { namespace Frontend {
class EmuWindow; class EmuWindow;
} }
@@ -24,7 +28,8 @@ class ShaderProgramManager;
class RasterizerOpenGL : public VideoCore::RasterizerAccelerated { class RasterizerOpenGL : public VideoCore::RasterizerAccelerated {
public: public:
explicit RasterizerOpenGL(Frontend::EmuWindow& emu_window, Driver& driver); explicit RasterizerOpenGL(Memory::MemorySystem& memory, Frontend::EmuWindow& emu_window,
Driver& driver);
~RasterizerOpenGL() override; ~RasterizerOpenGL() override;
void LoadDiskResources(const std::atomic_bool& stop_loading, void LoadDiskResources(const std::atomic_bool& stop_loading,
@@ -35,6 +40,7 @@ public:
void FlushRegion(PAddr addr, u32 size) override; void FlushRegion(PAddr addr, u32 size) override;
void InvalidateRegion(PAddr addr, u32 size) override; void InvalidateRegion(PAddr addr, u32 size) override;
void FlushAndInvalidateRegion(PAddr addr, u32 size) override; void FlushAndInvalidateRegion(PAddr addr, u32 size) override;
void ClearAll(bool flush) override;
bool AccelerateDisplayTransfer(const GPU::Regs::DisplayTransferConfig& config) override; bool AccelerateDisplayTransfer(const GPU::Regs::DisplayTransferConfig& config) override;
bool AccelerateTextureCopy(const GPU::Regs::DisplayTransferConfig& config) override; bool AccelerateTextureCopy(const GPU::Regs::DisplayTransferConfig& config) override;
bool AccelerateFill(const GPU::Regs::MemoryFillConfig& config) override; bool AccelerateFill(const GPU::Regs::MemoryFillConfig& config) override;
@@ -132,6 +138,7 @@ private:
bool SetupGeometryShader(); bool SetupGeometryShader();
private: private:
Memory::MemorySystem& memory;
Driver& driver; Driver& driver;
OpenGLState state; OpenGLState state;
TextureRuntime runtime; TextureRuntime runtime;

View File

@@ -273,9 +273,10 @@ static std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(const float width, cons
return matrix; return matrix;
} }
RendererOpenGL::RendererOpenGL(Frontend::EmuWindow& window, Frontend::EmuWindow* secondary_window) RendererOpenGL::RendererOpenGL(Memory::MemorySystem& memory_, Frontend::EmuWindow& window,
: RendererBase{window, secondary_window}, driver{Settings::values.graphics_api.GetValue() == Frontend::EmuWindow* secondary_window)
Settings::GraphicsAPI::OpenGLES, : RendererBase{window, secondary_window}, memory{memory_},
driver{Settings::values.graphics_api.GetValue() == Settings::GraphicsAPI::OpenGLES,
Settings::values.renderer_debug.GetValue()}, Settings::values.renderer_debug.GetValue()},
frame_dumper(Core::System::GetInstance().VideoDumper(), window) { frame_dumper(Core::System::GetInstance().VideoDumper(), window) {
window.mailbox = std::make_unique<OGLTextureMailbox>(); window.mailbox = std::make_unique<OGLTextureMailbox>();
@@ -294,7 +295,7 @@ VideoCore::ResultStatus RendererOpenGL::Init() {
} }
InitOpenGLObjects(); InitOpenGLObjects();
rasterizer = std::make_unique<RasterizerOpenGL>(render_window, driver); rasterizer = std::make_unique<RasterizerOpenGL>(memory, render_window, driver);
return VideoCore::ResultStatus::Success; return VideoCore::ResultStatus::Success;
} }
@@ -495,8 +496,7 @@ void RendererOpenGL::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& fram
screen_info.display_texcoords = Common::Rectangle<float>(0.f, 0.f, 1.f, 1.f); screen_info.display_texcoords = Common::Rectangle<float>(0.f, 0.f, 1.f, 1.f);
Memory::RasterizerFlushRegion(framebuffer_addr, framebuffer.stride * framebuffer.height); Memory::RasterizerFlushRegion(framebuffer_addr, framebuffer.stride * framebuffer.height);
const u8* framebuffer_data = memory.GetPhysicalPointer(framebuffer_addr);
const u8* framebuffer_data = VideoCore::g_memory->GetPhysicalPointer(framebuffer_addr);
state.texture_units[0].texture_2d = screen_info.texture.resource.handle; state.texture_units[0].texture_2d = screen_info.texture.resource.handle;
state.Apply(); state.Apply();

View File

@@ -16,6 +16,10 @@ namespace Layout {
struct FramebufferLayout; struct FramebufferLayout;
} }
namespace Memory {
class MemorySystem;
}
namespace Frontend { namespace Frontend {
struct Frame { struct Frame {
@@ -57,7 +61,8 @@ class RasterizerOpenGL;
class RendererOpenGL : public RendererBase { class RendererOpenGL : public RendererBase {
public: public:
explicit RendererOpenGL(Frontend::EmuWindow& window, Frontend::EmuWindow* secondary_window); explicit RendererOpenGL(Memory::MemorySystem& memory, Frontend::EmuWindow& window,
Frontend::EmuWindow* secondary_window);
~RendererOpenGL() override; ~RendererOpenGL() override;
VideoCore::ResultStatus Init() override; VideoCore::ResultStatus Init() override;
@@ -116,6 +121,7 @@ private:
void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, const TextureInfo& texture); void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, const TextureInfo& texture);
private: private:
Memory::MemorySystem& memory;
Driver driver; Driver driver;
OpenGLState state; OpenGLState state;
std::unique_ptr<RasterizerOpenGL> rasterizer; std::unique_ptr<RasterizerOpenGL> rasterizer;

View File

@@ -100,8 +100,9 @@ std::string BuildCommaSeparatedExtensions(std::vector<std::string> available_ext
} // Anonymous namespace } // Anonymous namespace
RendererVulkan::RendererVulkan(Frontend::EmuWindow& window, Frontend::EmuWindow* secondary_window) RendererVulkan::RendererVulkan(Memory::MemorySystem& memory_, Frontend::EmuWindow& window,
: RendererBase{window, secondary_window}, Frontend::EmuWindow* secondary_window)
: RendererBase{window, secondary_window}, memory{memory_},
telemetry_session{Core::System::GetInstance().TelemetrySession()}, telemetry_session{Core::System::GetInstance().TelemetrySession()},
instance{window, Settings::values.physical_device.GetValue()}, scheduler{instance, instance{window, Settings::values.physical_device.GetValue()}, scheduler{instance,
renderpass_cache}, renderpass_cache},
@@ -110,7 +111,8 @@ RendererVulkan::RendererVulkan(Frontend::EmuWindow& window, Frontend::EmuWindow*
renderpass_cache}, renderpass_cache},
vertex_buffer{instance, scheduler, vk::BufferUsageFlagBits::eVertexBuffer, vertex_buffer{instance, scheduler, vk::BufferUsageFlagBits::eVertexBuffer,
VERTEX_BUFFER_SIZE}, VERTEX_BUFFER_SIZE},
rasterizer{render_window, instance, scheduler, desc_manager, runtime, renderpass_cache} { rasterizer{memory, render_window, instance, scheduler,
desc_manager, runtime, renderpass_cache} {
Report(); Report();
window.mailbox = std::make_unique<TextureMailbox>(instance, swapchain, renderpass_cache); window.mailbox = std::make_unique<TextureMailbox>(instance, swapchain, renderpass_cache);
} }

View File

@@ -23,12 +23,19 @@ namespace Core {
class TelemetrySession; class TelemetrySession;
} }
namespace Memory {
class MemorySystem;
}
namespace Layout { namespace Layout {
struct FramebufferLayout; struct FramebufferLayout;
} }
namespace Vulkan { namespace Vulkan {
/**
* Structure used for storing information about the textures for each 3DS screen
**/
struct TextureInfo { struct TextureInfo {
u32 width; u32 width;
u32 height; u32 height;
@@ -38,6 +45,9 @@ struct TextureInfo {
VmaAllocation allocation; VmaAllocation allocation;
}; };
/**
* Structure used for storing information about the display target for each 3DS screen
**/
struct ScreenInfo { struct ScreenInfo {
TextureInfo texture; TextureInfo texture;
Common::Rectangle<f32> texcoords; Common::Rectangle<f32> texcoords;
@@ -50,7 +60,8 @@ class RendererVulkan : public RendererBase {
static constexpr std::size_t PRESENT_PIPELINES = 3; static constexpr std::size_t PRESENT_PIPELINES = 3;
public: public:
explicit RendererVulkan(Frontend::EmuWindow& window, Frontend::EmuWindow* secondary_window); explicit RendererVulkan(Memory::MemorySystem& memory, Frontend::EmuWindow& window,
Frontend::EmuWindow* secondary_window);
~RendererVulkan() override; ~RendererVulkan() override;
VideoCore::ResultStatus Init() override; VideoCore::ResultStatus Init() override;
@@ -111,6 +122,7 @@ private:
void LoadColorToActiveVkTexture(u8 color_r, u8 color_g, u8 color_b, const TextureInfo& texture); void LoadColorToActiveVkTexture(u8 color_r, u8 color_g, u8 color_b, const TextureInfo& texture);
private: private:
Memory::MemorySystem& memory;
Core::TelemetrySession& telemetry_session; Core::TelemetrySession& telemetry_session;
Instance instance; Instance instance;

View File

@@ -57,11 +57,12 @@ struct DrawParams {
return std::min(max_size, TEXTURE_BUFFER_SIZE); return std::min(max_size, TEXTURE_BUFFER_SIZE);
} }
RasterizerVulkan::RasterizerVulkan(Frontend::EmuWindow& emu_window, const Instance& instance, RasterizerVulkan::RasterizerVulkan(Memory::MemorySystem& memory_, Frontend::EmuWindow& emu_window,
Scheduler& scheduler, DescriptorManager& desc_manager, const Instance& instance, Scheduler& scheduler,
TextureRuntime& runtime, RenderpassCache& renderpass_cache) DescriptorManager& desc_manager, TextureRuntime& runtime,
: instance{instance}, scheduler{scheduler}, runtime{runtime}, RenderpassCache& renderpass_cache)
renderpass_cache{renderpass_cache}, desc_manager{desc_manager}, res_cache{*this, runtime}, : memory{memory_}, instance{instance}, scheduler{scheduler}, runtime{runtime},
renderpass_cache{renderpass_cache}, desc_manager{desc_manager}, res_cache{memory, runtime},
pipeline_cache{instance, scheduler, renderpass_cache, desc_manager}, pipeline_cache{instance, scheduler, renderpass_cache, desc_manager},
null_surface{NULL_PARAMS, vk::Format::eR8G8B8A8Unorm, NULL_USAGE, null_surface{NULL_PARAMS, vk::Format::eR8G8B8A8Unorm, NULL_USAGE,
vk::ImageAspectFlagBits::eColor, runtime}, vk::ImageAspectFlagBits::eColor, runtime},
@@ -235,7 +236,7 @@ void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_mi
const u32 data_size = loader.byte_count * vertex_num; const u32 data_size = loader.byte_count * vertex_num;
res_cache.FlushRegion(data_addr, data_size); res_cache.FlushRegion(data_addr, data_size);
const u8* src_ptr = VideoCore::g_memory->GetPhysicalPointer(data_addr); const u8* src_ptr = memory.GetPhysicalPointer(data_addr);
u8* dst_ptr = array_ptr + buffer_offset; u8* dst_ptr = array_ptr + buffer_offset;
// Align stride up if required by Vulkan implementation. // Align stride up if required by Vulkan implementation.
@@ -270,6 +271,9 @@ void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_mi
// Bind the generated bindings // Bind the generated bindings
scheduler.Record([this, binding_count = layout.binding_count, scheduler.Record([this, binding_count = layout.binding_count,
vertex_offsets = binding_offsets](vk::CommandBuffer cmdbuf) { vertex_offsets = binding_offsets](vk::CommandBuffer cmdbuf) {
for (auto& offset : vertex_offsets) {
ASSERT_MSG(offset != 0x8000000, "Bad offset");
}
cmdbuf.bindVertexBuffers(0, binding_count, vertex_buffers.data(), vertex_offsets.data()); cmdbuf.bindVertexBuffers(0, binding_count, vertex_buffers.data(), vertex_offsets.data());
}); });
} }
@@ -425,8 +429,8 @@ void RasterizerVulkan::SetupIndexArray() {
const vk::IndexType index_type = native_u8 ? vk::IndexType::eUint8EXT : vk::IndexType::eUint16; const vk::IndexType index_type = native_u8 ? vk::IndexType::eUint8EXT : vk::IndexType::eUint16;
const u32 index_buffer_size = regs.pipeline.num_vertices * (native_u8 ? 1 : 2); const u32 index_buffer_size = regs.pipeline.num_vertices * (native_u8 ? 1 : 2);
const u8* index_data = VideoCore::g_memory->GetPhysicalPointer( const u8* index_data =
regs.pipeline.vertex_attributes.GetPhysicalBaseAddress() + memory.GetPhysicalPointer(regs.pipeline.vertex_attributes.GetPhysicalBaseAddress() +
regs.pipeline.index_array.offset); regs.pipeline.index_array.offset);
auto [index_ptr, index_offset, _] = stream_buffer.Map(index_buffer_size, 2); auto [index_ptr, index_offset, _] = stream_buffer.Map(index_buffer_size, 2);
@@ -852,6 +856,10 @@ void RasterizerVulkan::FlushAndInvalidateRegion(PAddr addr, u32 size) {
res_cache.InvalidateRegion(addr, size, nullptr); res_cache.InvalidateRegion(addr, size, nullptr);
} }
void RasterizerVulkan::ClearAll(bool flush) {
res_cache.ClearAll(flush);
}
MICROPROFILE_DEFINE(Vulkan_Blits, "Vulkan", "Blits", MP_RGB(100, 100, 255)); MICROPROFILE_DEFINE(Vulkan_Blits, "Vulkan", "Blits", MP_RGB(100, 100, 255));
bool RasterizerVulkan::AccelerateDisplayTransfer(const GPU::Regs::DisplayTransferConfig& config) { bool RasterizerVulkan::AccelerateDisplayTransfer(const GPU::Regs::DisplayTransferConfig& config) {
MICROPROFILE_SCOPE(Vulkan_Blits); MICROPROFILE_SCOPE(Vulkan_Blits);

View File

@@ -15,6 +15,10 @@ namespace Frontend {
class EmuWindow; class EmuWindow;
} }
namespace Memory {
class MemorySystem;
}
namespace Vulkan { namespace Vulkan {
struct ScreenInfo; struct ScreenInfo;
@@ -58,9 +62,10 @@ class RasterizerVulkan : public VideoCore::RasterizerAccelerated {
friend class RendererVulkan; friend class RendererVulkan;
public: public:
explicit RasterizerVulkan(Frontend::EmuWindow& emu_window, const Instance& instance, explicit RasterizerVulkan(Memory::MemorySystem& memory, Frontend::EmuWindow& emu_window,
Scheduler& scheduler, DescriptorManager& desc_manager, const Instance& instance, Scheduler& scheduler,
TextureRuntime& runtime, RenderpassCache& renderpass_cache); DescriptorManager& desc_manager, TextureRuntime& runtime,
RenderpassCache& renderpass_cache);
~RasterizerVulkan() override; ~RasterizerVulkan() override;
void LoadDiskResources(const std::atomic_bool& stop_loading, void LoadDiskResources(const std::atomic_bool& stop_loading,
@@ -71,6 +76,7 @@ public:
void FlushRegion(PAddr addr, u32 size) override; void FlushRegion(PAddr addr, u32 size) override;
void InvalidateRegion(PAddr addr, u32 size) override; void InvalidateRegion(PAddr addr, u32 size) override;
void FlushAndInvalidateRegion(PAddr addr, u32 size) override; void FlushAndInvalidateRegion(PAddr addr, u32 size) override;
void ClearAll(bool flush) override;
bool AccelerateDisplayTransfer(const GPU::Regs::DisplayTransferConfig& config) override; bool AccelerateDisplayTransfer(const GPU::Regs::DisplayTransferConfig& config) override;
bool AccelerateTextureCopy(const GPU::Regs::DisplayTransferConfig& config) override; bool AccelerateTextureCopy(const GPU::Regs::DisplayTransferConfig& config) override;
bool AccelerateFill(const GPU::Regs::MemoryFillConfig& config) override; bool AccelerateFill(const GPU::Regs::MemoryFillConfig& config) override;
@@ -151,6 +157,7 @@ private:
vk::Sampler CreateSampler(const SamplerInfo& info); vk::Sampler CreateSampler(const SamplerInfo& info);
private: private:
Memory::MemorySystem& memory;
const Instance& instance; const Instance& instance;
Scheduler& scheduler; Scheduler& scheduler;
TextureRuntime& runtime; TextureRuntime& runtime;

View File

@@ -40,10 +40,10 @@ ResultStatus Init(Frontend::EmuWindow& emu_window, Frontend::EmuWindow* secondar
case Settings::GraphicsAPI::OpenGL: case Settings::GraphicsAPI::OpenGL:
case Settings::GraphicsAPI::OpenGLES: case Settings::GraphicsAPI::OpenGLES:
OpenGL::GLES = graphics_api == Settings::GraphicsAPI::OpenGLES; OpenGL::GLES = graphics_api == Settings::GraphicsAPI::OpenGLES;
g_renderer = std::make_unique<OpenGL::RendererOpenGL>(emu_window, secondary_window); g_renderer = std::make_unique<OpenGL::RendererOpenGL>(memory, emu_window, secondary_window);
break; break;
case Settings::GraphicsAPI::Vulkan: case Settings::GraphicsAPI::Vulkan:
g_renderer = std::make_unique<Vulkan::RendererVulkan>(emu_window, secondary_window); g_renderer = std::make_unique<Vulkan::RendererVulkan>(memory, emu_window, secondary_window);
break; break;
default: default:
LOG_CRITICAL(Render, "Invalid graphics API enum value {}", graphics_api); LOG_CRITICAL(Render, "Invalid graphics API enum value {}", graphics_api);