diff --git a/externals/microprofile/microprofile.h b/externals/microprofile/microprofile.h index 7b54ccf86..81f43e07e 100644 --- a/externals/microprofile/microprofile.h +++ b/externals/microprofile/microprofile.h @@ -832,7 +832,7 @@ struct MicroProfile #define MP_LOG_LEAVE 0x0 -inline int MicroProfileLogType(MicroProfileLogEntry Index) +inline uint64_t MicroProfileLogType(MicroProfileLogEntry Index) { return ((MP_LOG_BEGIN_MASK & Index)>>62) & 0x3; } @@ -845,7 +845,7 @@ inline uint64_t MicroProfileLogTimerIndex(MicroProfileLogEntry Index) inline MicroProfileLogEntry MicroProfileMakeLogIndex(uint64_t nBegin, MicroProfileToken nToken, int64_t nTick) { MicroProfileLogEntry Entry = (nBegin<<62) | ((0x3fff&nToken)<<48) | (MP_LOG_TICK_MASK&nTick); - int t = MicroProfileLogType(Entry); + uint64_t t = MicroProfileLogType(Entry); uint64_t nTimerIndex = MicroProfileLogTimerIndex(Entry); MP_ASSERT(t == nBegin); MP_ASSERT(nTimerIndex == (nToken&0x3fff)); diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 314bb5f8e..ba164dca1 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -763,7 +763,7 @@ void GMainWindow::ConnectMenuEvents() { connect(ui->action_Close_Movie, &QAction::triggered, this, &GMainWindow::OnCloseMovie); connect(ui->action_Save_Movie, &QAction::triggered, this, &GMainWindow::OnSaveMovie); connect(ui->action_Movie_Read_Only_Mode, &QAction::toggled, this, - [this](bool checked) { Core::Movie::GetInstance().SetReadOnly(checked); }); + [](bool checked) { Core::Movie::GetInstance().SetReadOnly(checked); }); connect(ui->action_Enable_Frame_Advancing, &QAction::triggered, this, [this] { if (emulation_running) { Core::System::GetInstance().frame_limiter.SetFrameAdvancing( @@ -1499,7 +1499,7 @@ void GMainWindow::InstallCIA(QStringList filepaths) { const auto cia_progress = [&](std::size_t written, std::size_t total) { emit UpdateProgress(written, total); }; - for (const auto current_path : filepaths) { + for (const auto& current_path : filepaths) { status = Service::AM::InstallCIA(current_path.toStdString(), cia_progress); emit CIAInstallReport(status, current_path); } @@ -1951,7 +1951,8 @@ void GMainWindow::OnCaptureScreenshot() { png_dialog.setAcceptMode(QFileDialog::AcceptSave); png_dialog.setDefaultSuffix(QStringLiteral("png")); if (png_dialog.exec()) { - const QString path = png_dialog.selectedFiles().first(); + const QList selected = png_dialog.selectedFiles(); + const QString path = selected.first(); if (!path.isEmpty()) { UISettings::values.screenshot_path = QFileInfo(path).path(); render_window->CaptureScreenshot(UISettings::values.screenshot_resolution_factor, path); diff --git a/src/core/core.cpp b/src/core/core.cpp index a11ec27ac..aacc797b7 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -436,7 +436,7 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo return ResultStatus::Success; } -RendererBase& System::Renderer() { +VideoCore::RendererBase& System::Renderer() { return *VideoCore::g_renderer; } diff --git a/src/core/core.h b/src/core/core.h index ed9d3b4f1..f7b7d53cc 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -57,7 +57,9 @@ namespace VideoDumper { class Backend; } +namespace VideoCore { class RendererBase; +} namespace Core { @@ -205,7 +207,7 @@ public: return *dsp_core; } - [[nodiscard]] RendererBase& Renderer(); + [[nodiscard]] VideoCore::RendererBase& Renderer(); /** * Gets a reference to the service manager. diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/archive_backend.h index e33c3c6b1..77f041d7e 100644 --- a/src/core/file_sys/archive_backend.h +++ b/src/core/file_sys/archive_backend.h @@ -101,7 +101,7 @@ struct ArchiveFormatInfo { u32_le number_files; ///< The pre-defined number of files in the archive. u8 duplicate_data; ///< Whether the archive should duplicate the data. }; -static_assert(std::is_pod::value, "ArchiveFormatInfo is not POD"); +static_assert(std::is_trivial_v, "ArchiveFormatInfo is not POD"); class ArchiveBackend : NonCopyable { public: diff --git a/src/video_core/pica.cpp b/src/video_core/pica.cpp index d2f8874fe..283cb330d 100644 --- a/src/video_core/pica.cpp +++ b/src/video_core/pica.cpp @@ -34,13 +34,13 @@ template void Zero(T& o) { static_assert(std::is_trivially_copyable_v, "It's undefined behavior to memset a non-trivially copyable type"); - memset(&o, 0, sizeof(o)); + std::memset(&o, 0, sizeof(o)); } State::State() : geometry_pipeline(*this) { auto SubmitVertex = [this](const Shader::AttributeBuffer& vertex) { using Pica::Shader::OutputVertex; - auto AddTriangle = [this](const OutputVertex& v0, const OutputVertex& v1, + auto AddTriangle = [](const OutputVertex& v0, const OutputVertex& v1, const OutputVertex& v2) { VideoCore::g_renderer->Rasterizer()->AddTriangle(v0, v1, v2); }; diff --git a/src/video_core/renderer_base.cpp b/src/video_core/renderer_base.cpp index e96a5dee4..6444b2e3b 100644 --- a/src/video_core/renderer_base.cpp +++ b/src/video_core/renderer_base.cpp @@ -10,6 +10,8 @@ #include "video_core/swrasterizer/swrasterizer.h" #include "video_core/video_core.h" +namespace VideoCore { + RendererBase::RendererBase(Frontend::EmuWindow& window) : render_window{window} {} RendererBase::~RendererBase() = default; void RendererBase::UpdateCurrentFramebufferLayout(bool is_portrait_mode) { @@ -33,3 +35,5 @@ void RendererBase::RefreshRasterizerSetting() { void RendererBase::Sync() { rasterizer->SyncEntireState(); } + +} // namespace VideoCore diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h index 9322742cf..b1612d82d 100644 --- a/src/video_core/renderer_base.h +++ b/src/video_core/renderer_base.h @@ -13,6 +13,8 @@ namespace Frontend { class EmuWindow; } +namespace VideoCore { + class RendererBase : NonCopyable { public: explicit RendererBase(Frontend::EmuWindow& window); @@ -75,3 +77,5 @@ protected: private: bool opengl_rasterizer_active = false; }; + +} // namespace VideoCore diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 2f04412a4..0e04a9fc6 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -43,10 +43,13 @@ static bool IsVendorAmd() { const std::string_view gpu_vendor{reinterpret_cast(glGetString(GL_VENDOR))}; return gpu_vendor == "ATI Technologies Inc." || gpu_vendor == "Advanced Micro Devices, Inc."; } + +#ifdef __APPLE__ static bool IsVendorIntel() { std::string gpu_vendor{reinterpret_cast(glGetString(GL_VENDOR))}; return gpu_vendor == "Intel Inc."; } +#endif RasterizerOpenGL::RasterizerOpenGL(Frontend::EmuWindow& emu_window) : is_amd(IsVendorAmd()), vertex_buffer(GL_ARRAY_BUFFER, VERTEX_BUFFER_SIZE, is_amd), @@ -758,8 +761,9 @@ bool RasterizerOpenGL::Draw(bool accelerate, bool is_indexed) { texture_cube_sampler.SyncWithConfig(texture.config); state.texture_units[texture_index].texture_2d = 0; continue; // Texture unit 0 setup finished. Continue to next unit + default: + state.texture_cube_unit.texture_cube = 0; } - state.texture_cube_unit.texture_cube = 0; } texture_samplers[texture_index].SyncWithConfig(texture.config); diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index 634d26ca4..1633bf8f0 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h @@ -57,7 +57,7 @@ struct PresentationTexture { OGLTexture texture; }; -class RendererOpenGL : public RendererBase { +class RendererOpenGL : public VideoCore::RendererBase { public: explicit RendererOpenGL(Frontend::EmuWindow& window); ~RendererOpenGL() override; diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index ce8545338..59f873a84 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -723,6 +723,14 @@ VideoCore::ResultStatus RendererVulkan::Init() { } /// Shutdown the renderer -void RendererVulkan::ShutDown() {} +void RendererVulkan::ShutDown() { + vertex_buffer.Destroy(); -} // namespace OpenGL + rasterizer.reset(); + swapchain.reset(); + g_vk_task_scheduler.reset(); + s_vulkan_state.reset(); + g_vk_instace.reset(); +} + +} // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index 22b883c70..103c03b1a 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h @@ -26,7 +26,7 @@ struct ScreenInfo { GPU::Regs::PixelFormat format; }; -class RendererVulkan : public RendererBase { +class RendererVulkan : public VideoCore::RendererBase { public: RendererVulkan(Frontend::EmuWindow& window); ~RendererVulkan() override = default; @@ -39,7 +39,7 @@ public: bool BeginPresent(); void EndPresent(); - void SwapBuffers(); + void SwapBuffers() override; void TryPresent(int timeout_ms) override {} void PrepareVideoDumping() override {} diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 08e82c8e4..b9aab87db 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -422,9 +422,6 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) { g_vk_task_scheduler->Submit(); - auto gpu_tick = g_vk_task_scheduler->GetGPUTick(); - auto cpu_tick = g_vk_task_scheduler->GetCPUTick(); - return true; } diff --git a/src/video_core/renderer_vulkan/vk_state.cpp b/src/video_core/renderer_vulkan/vk_state.cpp index 2ee0de828..1cc171b0a 100644 --- a/src/video_core/renderer_vulkan/vk_state.cpp +++ b/src/video_core/renderer_vulkan/vk_state.cpp @@ -13,7 +13,7 @@ namespace Vulkan { -std::unique_ptr s_vulkan_state{}; +std::unique_ptr s_vulkan_state; auto IsStencil = [](vk::Format format) -> bool { switch (format) { @@ -144,6 +144,18 @@ VulkanState::~VulkanState() { // Destroy samplers device.destroySampler(render_sampler); device.destroySampler(present_sampler); + + // Destroy shaders + for (auto& shader : render_fragment_shaders) { + device.destroyShaderModule(shader.second); + } + + // Destroy pipelines + for (auto& pipeline : render_pipelines) { + device.destroyPipeline(pipeline.second); + } + + device.destroyPipeline(present_pipeline); } void VulkanState::Create(const std::shared_ptr& swapchain) { @@ -445,19 +457,19 @@ void VulkanState::ApplyRenderState(const Pica::Regs& regs) { // Try to use an already complete pipeline vk::Pipeline pipeline; if (result != render_pipelines.end()) { - pipeline = result->second.get(); + pipeline = result->second; } else { // Maybe the shader has been compiled but the pipeline state changed? auto shader = render_fragment_shaders.find(render_pipeline_key.fragment_config); if (shader != render_fragment_shaders.end()) { - render_pipeline_builder.SetShaderStage(vk::ShaderStageFlagBits::eFragment, shader->second.get()); + render_pipeline_builder.SetShaderStage(vk::ShaderStageFlagBits::eFragment, shader->second); } else { // Re-compile shader module and create new pipeline auto code = GenerateFragmentShader(render_pipeline_key.fragment_config); auto module = CompileShader(code, vk::ShaderStageFlagBits::eFragment); - render_fragment_shaders.emplace(render_pipeline_key.fragment_config, vk::UniqueShaderModule{module}); + render_fragment_shaders.emplace(render_pipeline_key.fragment_config, module); render_pipeline_builder.SetShaderStage(vk::ShaderStageFlagBits::eFragment, module); } @@ -470,7 +482,7 @@ void VulkanState::ApplyRenderState(const Pica::Regs& regs) { att.alphaBlendOp, att.colorWriteMask); // Cache the resulted pipeline pipeline = render_pipeline_builder.Build(); - render_pipelines.emplace(render_pipeline_key, vk::UniquePipeline{pipeline}); + render_pipelines.emplace(render_pipeline_key, pipeline); } // Bind the render pipeline @@ -502,7 +514,7 @@ void VulkanState::ApplyPresentState() { // Bind present pipeline and descriptors auto cmdbuffer = g_vk_task_scheduler->GetRenderCommandBuffer(); - cmdbuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, present_pipeline.get()); + cmdbuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, present_pipeline); ApplyCommonState(false); @@ -686,7 +698,7 @@ void VulkanState::ConfigurePresentPipeline() { present_fragment_shader = CompileShader(fragment_code, vk::ShaderStageFlagBits::eFragment); present_pipeline_builder.SetShaderStage(vk::ShaderStageFlagBits::eFragment, present_fragment_shader); - present_pipeline = vk::UniquePipeline{present_pipeline_builder.Build()}; + present_pipeline = present_pipeline_builder.Build(); } } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_state.h b/src/video_core/renderer_vulkan/vk_state.h index 89eeb3a2a..93fc0679d 100644 --- a/src/video_core/renderer_vulkan/vk_state.h +++ b/src/video_core/renderer_vulkan/vk_state.h @@ -141,12 +141,12 @@ private: PipelineCacheKey render_pipeline_key{}; PipelineBuilder render_pipeline_builder, present_pipeline_builder; vk::PipelineLayout render_pipeline_layout, present_pipeline_layout; - std::unordered_map render_pipelines; - vk::UniquePipeline present_pipeline; + std::unordered_map render_pipelines; + vk::Pipeline present_pipeline; // Shader caches vk::ShaderModule render_vertex_shader, present_vertex_shader, present_fragment_shader; - std::unordered_map render_fragment_shaders; + std::unordered_map render_fragment_shaders; // Dynamic state enum DynamicStateFlags : u32 { @@ -177,4 +177,6 @@ private: std::array blend_constants{}; }; +extern std::unique_ptr s_vulkan_state; + } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_task_scheduler.cpp b/src/video_core/renderer_vulkan/vk_task_scheduler.cpp index 56204f124..dffc87390 100644 --- a/src/video_core/renderer_vulkan/vk_task_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_task_scheduler.cpp @@ -15,13 +15,14 @@ VKTaskScheduler::~VKTaskScheduler() { auto device = g_vk_instace->GetDevice(); device.waitIdle(); + for (auto& task : tasks) { + task.staging.Destroy(); + device.destroyDescriptorPool(task.pool); + } + SyncToGPU(); device.destroyCommandPool(command_pool); device.destroySemaphore(timeline); - - for (auto& task : tasks) { - device.destroyDescriptorPool(task.pool); - } } std::tuple VKTaskScheduler::RequestStaging(u32 size) { @@ -111,7 +112,8 @@ vk::DescriptorPool VKTaskScheduler::GetDescriptorPool() const { void VKTaskScheduler::SyncToGPU(u64 task_index) { // No need to sync if the GPU already has finished the task - if (tasks[task_index].task_id <= GetGPUTick()) { + auto tick = GetGPUTick(); + if (tasks[task_index].task_id <= tick) { return; } @@ -162,11 +164,11 @@ void VKTaskScheduler::Submit(bool wait_completion, bool present, VKSwapChain* sw } const u32 num_signal_semaphores = present ? 2U : 1U; - const std::array signal_values{task.task_id, u64(0)}; + const std::array signal_values{task.task_id + 1, u64(0)}; std::array signal_semaphores{timeline, vk::Semaphore{}}; const u32 num_wait_semaphores = present ? 2U : 1U; - const std::array wait_values{task.task_id - 1, u64(1)}; + const std::array wait_values{task.task_id, u64(1)}; std::array wait_semaphores{timeline, vk::Semaphore{}}; // When the task completes the timeline will increment to the task id @@ -224,7 +226,7 @@ void VKTaskScheduler::BeginTask() { // Move to the next command buffer. current_task = next_task_index; - task.task_id = current_task_id++; + task.task_id = ++current_task_id; task.current_offset = 0; task.use_upload_buffer = false; diff --git a/src/video_core/renderer_vulkan/vk_task_scheduler.h b/src/video_core/renderer_vulkan/vk_task_scheduler.h index 228d7b442..6e6f916a9 100644 --- a/src/video_core/renderer_vulkan/vk_task_scheduler.h +++ b/src/video_core/renderer_vulkan/vk_task_scheduler.h @@ -20,7 +20,7 @@ namespace Vulkan { -constexpr u32 TASK_COUNT = 3; +constexpr u32 TASK_COUNT = 5; constexpr u32 STAGING_BUFFER_SIZE = 16 * 1024 * 1024; class VKSwapChain; @@ -60,8 +60,8 @@ public: private: struct Task { - bool use_upload_buffer{false}; - u64 current_offset{}, task_id{}; + bool use_upload_buffer = false; + u64 current_offset = 0, task_id = 0; std::array command_buffers; std::vector> cleanups; vk::DescriptorPool pool; @@ -70,11 +70,11 @@ private: vk::Semaphore timeline; vk::CommandPool command_pool; - u64 current_task_id = 1; + u64 current_task_id = -1; // Each task contains unique resources std::array tasks; - u64 current_task = 0; + u64 current_task = TASK_COUNT - 1; }; extern std::unique_ptr g_vk_task_scheduler; diff --git a/src/video_core/shader/shader.h b/src/video_core/shader/shader.h index 05a1e8b80..3dde933a1 100644 --- a/src/video_core/shader/shader.h +++ b/src/video_core/shader/shader.h @@ -91,7 +91,7 @@ ASSERT_POS(tc0_w, RasterizerRegs::VSOutputAttributes::TEXCOORD0_W); ASSERT_POS(view, RasterizerRegs::VSOutputAttributes::VIEW_X); ASSERT_POS(tc2, RasterizerRegs::VSOutputAttributes::TEXCOORD2_U); #undef ASSERT_POS -static_assert(std::is_pod::value, "Structure is not POD"); +static_assert(std::is_trivial_v, "Structure is not POD"); static_assert(sizeof(OutputVertex) == 24 * sizeof(float), "OutputVertex has invalid size"); /** @@ -153,7 +153,7 @@ struct UnitState { ar& output; } } registers; - static_assert(std::is_pod::value, "Structure is not POD"); + static_assert(std::is_trivial_v, "Structure is not POD"); bool conditional_code[2]; diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h index 9e12cfda6..8534859b8 100644 --- a/src/video_core/video_core.h +++ b/src/video_core/video_core.h @@ -6,6 +6,7 @@ #include #include +#include #include #include "core/frontend/emu_window.h" @@ -13,8 +14,6 @@ namespace Frontend { class EmuWindow; } -class RendererBase; - namespace Memory { class MemorySystem; } @@ -24,6 +23,7 @@ class MemorySystem; namespace VideoCore { +class RendererBase; extern std::unique_ptr g_renderer; ///< Renderer plugin // TODO: Wrap these in a user settings struct along with any other graphics settings (often set from