diff options
author | Stelios Tsampas | 2019-12-15 01:45:05 +0200 |
---|---|---|
committer | Stelios Tsampas | 2019-12-15 01:45:05 +0200 |
commit | e2fc54e0c24a50beef281f4edc11050387a6983a (patch) | |
tree | 0d0ce8653a8a8474031e4abfc648004a6b92a7a8 | |
parent | ccd8f512f1a6c7c5a7aed45cbcec9d62766fdc0d (diff) | |
download | aur-e2fc54e0c24a50beef281f4edc11050387a6983a.tar.gz |
version 0.40. Enable extra optimizations.
-rw-r--r-- | .SRCINFO | 10 | ||||
-rw-r--r-- | PKGBUILD | 44 | ||||
-rw-r--r-- | dxvk-async.patch | 373 | ||||
-rw-r--r-- | dxvk-mangohud.patch | 665 | ||||
-rw-r--r-- | extraopts.patch | 70 |
5 files changed, 866 insertions, 296 deletions
@@ -1,6 +1,6 @@ pkgbase = d9vk-mingw pkgdesc = A d3d9 to vk layer based off DXVK's codebase, mingw version - pkgver = 0.40.rc.p + pkgver = 0.40 pkgrel = 1 url = https://github.com/Joshua-Ashton/d9vk arch = x86_64 @@ -17,12 +17,16 @@ pkgbase = d9vk-mingw depends = bash provides = d9vk conflicts = d9vk - source = git+https://github.com/Joshua-Ashton/d9vk.git#tag=0.40-rc-p + source = git+https://github.com/Joshua-Ashton/d9vk.git#tag=0.40 source = setup_d9vk source = dxvk-async.patch + source = dxvk-mangohud.patch + source = extraopts.patch sha256sums = SKIP sha256sums = 7147644664ef33d04f7b18683c47be95b5664c57cf6d63fdc019d915deebd37a - sha256sums = 757fd5ca3faf476730891541de408593450fe4b490cc87bd90b342826d66c564 + sha256sums = 6ff286091c20327e67252e1e6812830a42c990d1ee56541023eb217712209f3c + sha256sums = 2e335237623aaf006f8814fc9712f3a4be0d678cd0714879a3a4545f3bbf41ce + sha256sums = acde3a23166f79fa87ab090200be2aabaf16e5876ce19b8270ad1179bb0bc7a5 pkgname = d9vk-mingw @@ -1,8 +1,8 @@ # Maintainer: loathingkernel <loathingkernel @at gmail .dot com> pkgname=d9vk-mingw -_tag=0.40-rc-p -pkgver=${_tag//-/.} +_tag=0.40 +pkgver=${_tag//-/_} pkgrel=1 pkgdesc="A d3d9 to vk layer based off DXVK's codebase, mingw version" arch=('x86_64') @@ -16,20 +16,56 @@ source=( "git+https://github.com/Joshua-Ashton/d9vk.git#tag=$_tag" "setup_d9vk" "dxvk-async.patch" + "dxvk-mangohud.patch" + "extraopts.patch" ) sha256sums=( "SKIP" "7147644664ef33d04f7b18683c47be95b5664c57cf6d63fdc019d915deebd37a" - "757fd5ca3faf476730891541de408593450fe4b490cc87bd90b342826d66c564" + "6ff286091c20327e67252e1e6812830a42c990d1ee56541023eb217712209f3c" + "2e335237623aaf006f8814fc9712f3a4be0d678cd0714879a3a4545f3bbf41ce" + "acde3a23166f79fa87ab090200be2aabaf16e5876ce19b8270ad1179bb0bc7a5" ) prepare() { cd d9vk + # If using -march=native and the CPU supports AVX, launching a d3d9 + # game can cause an Unhandled exception. The cause seems to be the + # combination of AVX instructions and tree vectorization (implied by O3), + # all tested archictures from sandybridge to haswell are affected. + # Disabling either AVX (and AVX2 as a side-effect) or tree + # vectorization fixes the issue. I am not sure which one is better + # to disable so below you can choose. Append either of these flags. + # Relevant Wine issues + # https://bugs.winehq.org/show_bug.cgi?id=45289 + # https://bugs.winehq.org/show_bug.cgi?id=43516 + CFLAGS+=" -mno-avx" + # CFLAGS+=" -fno-tree-vectorize" + # Patch crossfiles with extra optimizations from makepkg.conf + # If building fails, comment the line below to disable them. + patch -p1 -i ../extraopts.patch + # Adjust optimization level in meson arguments. This is ignored + # anyways because meson sets its own optimization level. + CFLAGS="${CFLAGS/ -O*([0-3])/}" + # Doesn't compile with these flags in MingW so remove them. + # They are also filtered in Wine PKGBUILDs so remove them + # for winelib versions too. + CFLAGS="${CFLAGS/ -fno-plt/}" + LDFLAGS="${LDFLAGS/,-z,relro,-z,now/}" + sed -i build-win64.txt \ + -e "s|@CARGS@|\'${CFLAGS// /\',\'}\'|g" \ + -e "s|@LDARGS@|\'${LDFLAGS// /\',\'}\'|g" + sed -i build-win32.txt \ + -e "s|@CARGS@|\'${CFLAGS// /\',\'}\'|g" \ + -e "s|@LDARGS@|\'${LDFLAGS// /\',\'}\'|g" # Uncomment to enable dxvk async patch. # Enable at your own risk. If you don't know what it is, # and its implications, leave it as is. You have been warned. # I am not liable if anything happens to you by using it. + # Patch enables async by default. YOU HAVE BEEN WARNED. #patch -p1 -i ../dxvk-async.patch + # Uncomment to enable Mango HUD for dxvk + #patch -p1 -i ../dxvk-mangohud.patch } build() { @@ -38,6 +74,7 @@ build() { --prefix "/usr/share/d9vk/x64" \ --bindir "" --libdir "" \ --buildtype "release" \ + --optimization=3 \ --strip \ -Denable_d3d10=false \ -Denable_d3d11=false \ @@ -50,6 +87,7 @@ build() { --prefix "/usr/share/d9vk/x32" \ --bindir "" --libdir "" \ --buildtype "release" \ + --optimization=3 \ --strip \ -Denable_d3d10=false \ -Denable_d3d11=false \ diff --git a/dxvk-async.patch b/dxvk-async.patch index 21bf8325ba7c..19c506c4964f 100644 --- a/dxvk-async.patch +++ b/dxvk-async.patch @@ -1,14 +1,15 @@ -From 653b6b9d25d41df41acb9d5d50e06bf8f45cc56c Mon Sep 17 00:00:00 2001 +From dfac76f528d0fc88ecbfe27ccb87483840828b9b Mon Sep 17 00:00:00 2001 From: Tk-Glitch <ti3nou@gmail.com> -Date: Mon, 15 Jul 2019 05:46:41 +0200 -Subject: async patchset rebase against a93dd74f +Date: Sat, 28 Sep 2019 18:59:04 +0200 +Subject: Async pipecompiler rebase against DXVK + d128d776ad906d6b8d3941eda7b7ee679346dbaf diff --git a/meson.build b/meson.build -index f7dcd491..31665f93 100644 +index 9a519e46..dea82ee1 100644 --- a/meson.build +++ b/meson.build -@@ -90,7 +90,7 @@ else +@@ -101,7 +101,7 @@ else endif dxvk_version = vcs_tag( @@ -18,10 +19,10 @@ index f7dcd491..31665f93 100644 output: 'version.h') diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp -index 6df6e3c3..bb802c96 100644 +index b4f679fa..13c86d8f 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp -@@ -648,7 +648,7 @@ namespace dxvk { +@@ -606,7 +606,7 @@ namespace dxvk { const Rc<DxvkImageView>& imageView, VkImageAspectFlags clearAspects, VkClearValue clearValue) { @@ -30,7 +31,7 @@ index 6df6e3c3..bb802c96 100644 // Prepare attachment ops DxvkColorAttachmentOps colorOp; -@@ -2406,7 +2406,7 @@ namespace dxvk { +@@ -2433,7 +2433,7 @@ namespace dxvk { VkExtent3D extent, VkImageAspectFlags aspect, VkClearValue value) { @@ -39,16 +40,16 @@ index 6df6e3c3..bb802c96 100644 // Find out if the render target view is currently bound, // so that we can avoid spilling the render pass if it is. -@@ -3527,7 +3527,7 @@ namespace dxvk { - // Retrieve and bind actual Vulkan pipeline handle - m_gpActivePipeline = m_state.gp.pipeline != nullptr && m_state.om.framebuffer != nullptr - ? m_state.gp.pipeline->getPipelineHandle(m_state.gp.state, -- m_state.om.framebuffer->getRenderPass()) -+ m_state.om.framebuffer->getRenderPass(), this->checkAsyncCompilationCompat()) - : VK_NULL_HANDLE; - - if (m_gpActivePipeline != VK_NULL_HANDLE) { -@@ -3794,7 +3794,7 @@ namespace dxvk { +@@ -3652,7 +3652,7 @@ namespace dxvk { + : DxvkContextFlag::GpDirtyStencilRef); + + // Retrieve and bind actual Vulkan pipeline handle +- m_gpActivePipeline = m_state.gp.pipeline->getPipelineHandle(m_state.gp.state, m_state.om.framebuffer->getRenderPass()); ++ m_gpActivePipeline = m_state.gp.pipeline->getPipelineHandle(m_state.gp.state, m_state.om.framebuffer->getRenderPass(), this->checkAsyncCompilationCompat()); + + if (unlikely(!m_gpActivePipeline)) + return false; +@@ -3969,7 +3969,7 @@ namespace dxvk { } @@ -56,8 +57,8 @@ index 6df6e3c3..bb802c96 100644 + void DxvkContext::updateFramebuffer(bool isDraw) { if (m_flags.test(DxvkContextFlag::GpDirtyFramebuffer)) { m_flags.clr(DxvkContextFlag::GpDirtyFramebuffer); - -@@ -3813,6 +3813,11 @@ namespace dxvk { + +@@ -3988,6 +3988,11 @@ namespace dxvk { : VkComponentMapping(); } @@ -69,7 +70,7 @@ index 6df6e3c3..bb802c96 100644 m_flags.set(DxvkContextFlag::GpDirtyPipelineState); } } -@@ -4040,7 +4045,7 @@ namespace dxvk { +@@ -4205,7 +4210,7 @@ namespace dxvk { template<bool Indexed> void DxvkContext::commitGraphicsState() { if (m_flags.test(DxvkContextFlag::GpDirtyFramebuffer)) @@ -78,7 +79,7 @@ index 6df6e3c3..bb802c96 100644 if (!m_flags.test(DxvkContextFlag::GpRenderPassBound)) this->startRenderPass(); -@@ -4288,4 +4293,13 @@ namespace dxvk { +@@ -4465,4 +4470,13 @@ namespace dxvk { } } @@ -95,10 +96,10 @@ index 6df6e3c3..bb802c96 100644 + } +} diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h -index 79a818e9..935cc5a4 100644 +index f54f5321..0984d085 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h -@@ -1138,7 +1138,7 @@ namespace dxvk { +@@ -1141,7 +1141,7 @@ namespace dxvk { VkDescriptorSet set, const DxvkPipelineLayout* layout); @@ -107,50 +108,21 @@ index 79a818e9..935cc5a4 100644 void updateIndexBufferBinding(); void updateVertexBufferBindings(); -@@ -1163,6 +1163,8 @@ namespace dxvk { - - void commitGraphicsPostBarriers(); +@@ -1180,6 +1180,7 @@ namespace dxvk { + + void trackDrawBuffer(); + bool checkAsyncCompilationCompat(); -+ - void emitMemoryBarrier( - VkPipelineStageFlags srcStages, - VkAccessFlags srcAccess, -diff --git a/src/dxvk/dxvk_framebuffer.h b/src/dxvk/dxvk_framebuffer.h -index 49133845..ff80297b 100644 ---- a/src/dxvk/dxvk_framebuffer.h -+++ b/src/dxvk/dxvk_framebuffer.h -@@ -120,8 +120,8 @@ namespace dxvk { - * \brief Retrieves render pass - * \returns Render pass reference - */ -- const DxvkRenderPass& getRenderPass() const { -- return *m_renderPass; -+ const Rc<DxvkRenderPass>& getRenderPass() const { -+ return m_renderPass; - } - - /** -@@ -221,4 +221,4 @@ namespace dxvk { - }; -} \ No newline at end of file +} diff --git a/src/dxvk/dxvk_graphics.cpp b/src/dxvk/dxvk_graphics.cpp -index 92403199..367b955c 100644 +index 5e05b425..8586c794 100644 --- a/src/dxvk/dxvk_graphics.cpp +++ b/src/dxvk/dxvk_graphics.cpp -@@ -4,6 +4,7 @@ - #include "dxvk_device.h" - #include "dxvk_graphics.h" - #include "dxvk_pipemanager.h" -+#include "dxvk_pipecompiler.h" - #include "dxvk_spec_const.h" - #include "dxvk_state_cache.h" - -@@ -79,8 +80,6 @@ namespace dxvk { +@@ -75,8 +75,6 @@ namespace dxvk { DxvkGraphicsPipeline::~DxvkGraphicsPipeline() { @@ -159,151 +131,38 @@ index 92403199..367b955c 100644 } -@@ -100,8 +99,9 @@ namespace dxvk { +@@ -96,7 +94,8 @@ namespace dxvk { VkPipeline DxvkGraphicsPipeline::getPipelineHandle( const DxvkGraphicsPipelineStateInfo& state, -- const DxvkRenderPass& renderPass) { -- VkRenderPass renderPassHandle = renderPass.getDefaultHandle(); -+ const Rc<DxvkRenderPass>& renderPass, +- const DxvkRenderPass* renderPass) { ++ const DxvkRenderPass* renderPass, + bool async) { -+ VkRenderPass renderPassHandle = renderPass->getDefaultHandle(); - - VkPipeline newPipelineHandle = VK_NULL_HANDLE; + DxvkGraphicsPipelineInstance* instance = nullptr; -@@ -119,26 +119,47 @@ namespace dxvk { + { std::lock_guard<sync::Spinlock> lock(m_mutex); +@@ -105,10 +104,13 @@ namespace dxvk { - // If no pipeline instance exists with the given state - // vector, create a new one and add it to the list. -- newPipelineHandle = this->compilePipeline(state, renderPass); -+ Rc<DxvkGraphicsPipelineInstance> newPipeline = -+ new DxvkGraphicsPipelineInstance(m_pipeMgr->m_device->vkd(), -+ state, renderPassHandle, VK_NULL_HANDLE); + if (instance) + return instance->pipeline(); +- +- instance = this->createInstance(state, renderPass); + + if (async && m_pipeMgr->m_compiler != nullptr) -+ m_pipeMgr->m_compiler->queueCompilation(this, newPipeline, renderPass); ++ m_pipeMgr->m_compiler->queueCompilation(this, state, renderPass); + else -+ newPipelineHandle = this->compileInstance(newPipeline, renderPass); - - // Add new pipeline to the set -- m_pipelines.emplace_back(state, renderPassHandle, newPipelineHandle); -+ m_pipelines.push_back(newPipeline); - m_pipeMgr->m_numGraphicsPipelines += 1; ++ instance = this->createInstance(state, renderPass); } - -- if (newPipelineHandle != VK_NULL_HANDLE) -- this->writePipelineStateToCache(state, renderPass.format()); -+ return newPipelineHandle; -+ } -+ -+ -+ VkPipeline DxvkGraphicsPipeline::compileInstance( -+ const Rc<DxvkGraphicsPipelineInstance>& instance, -+ const Rc<DxvkRenderPass>& renderPass) { -+ VkPipeline newPipelineHandle = this->compilePipeline( -+ instance->m_stateVector, *renderPass); -+ -+ if (!instance->setPipeline(newPipelineHandle)) { -+ m_vkd->vkDestroyPipeline(m_vkd->device(), newPipelineHandle, nullptr); -+ } else { -+ if (newPipelineHandle != VK_NULL_HANDLE) -+ this->writePipelineStateToCache(instance->m_stateVector, renderPass->format()); -+ } - - return newPipelineHandle; - } - - -- const DxvkGraphicsPipelineInstance* DxvkGraphicsPipeline::findInstance( -+ DxvkGraphicsPipelineInstance* DxvkGraphicsPipeline::findInstance( - const DxvkGraphicsPipelineStateInfo& state, - VkRenderPass renderPass) const { - for (const auto& instance : m_pipelines) { -- if (instance.isCompatible(state, renderPass)) -- return &instance; -+ if (instance->isCompatible(state, renderPass)) -+ return instance.ptr(); - } - - return nullptr; +- ++ + if (!instance) + return VK_NULL_HANDLE; + diff --git a/src/dxvk/dxvk_graphics.h b/src/dxvk/dxvk_graphics.h -index 976cf590..2d0fbd2b 100644 +index 168e9714..07f0883d 100644 --- a/src/dxvk/dxvk_graphics.h +++ b/src/dxvk/dxvk_graphics.h -@@ -132,8 +132,8 @@ namespace dxvk { - * Stores a state vector and the - * corresponding pipeline handle. - */ -- class DxvkGraphicsPipelineInstance { -- -+ class DxvkGraphicsPipelineInstance: public RcObject { -+ friend class DxvkGraphicsPipeline; - public: - - DxvkGraphicsPipelineInstance() -@@ -141,13 +141,19 @@ namespace dxvk { - m_renderPass (VK_NULL_HANDLE), - m_pipeline (VK_NULL_HANDLE) { } - DxvkGraphicsPipelineInstance( -+ const Rc<vk::DeviceFn>& vkd, - const DxvkGraphicsPipelineStateInfo& state, - VkRenderPass rp, - VkPipeline pipe) -- : m_stateVector (state), -+ : m_vkd (vkd), -+ m_stateVector (state), - m_renderPass (rp), - m_pipeline (pipe) { } - -+ ~DxvkGraphicsPipelineInstance() { -+ m_vkd->vkDestroyPipeline(m_vkd->device(), m_pipeline, nullptr); -+ } -+ - /** - * \brief Checks for matching pipeline state - * -@@ -162,23 +168,38 @@ namespace dxvk { - && m_renderPass == rp; - } - -+ /** -+ * \brief Sets the pipeline handle -+ * -+ * If a pipeline handle has already been -+ * set up, this method will fail and the new pipeline -+ * handle should be destroyed. -+ * \param [in] pipeline The pipeline -+ */ -+ bool setPipeline(VkPipeline pipeline) { -+ VkPipeline expected = VK_NULL_HANDLE; -+ return m_pipeline.compare_exchange_strong(expected, pipeline); -+ } -+ - /** - * \brief Retrieves pipeline - * \returns The pipeline handle - */ - VkPipeline pipeline() const { -- return m_pipeline; -+ return m_pipeline.load(); - } - - private: - -+ const Rc<vk::DeviceFn> m_vkd; - DxvkGraphicsPipelineStateInfo m_stateVector; - VkRenderPass m_renderPass; -- VkPipeline m_pipeline; -+ std::atomic<VkPipeline> m_pipeline; - - }; - - -+ - /** - * \brief Graphics pipeline - * -@@ -237,19 +258,19 @@ namespace dxvk { +@@ -247,11 +247,13 @@ namespace dxvk { * state. If necessary, a new pipeline will be created. * \param [in] state Pipeline state vector * \param [in] renderPass The render pass @@ -312,50 +171,17 @@ index 976cf590..2d0fbd2b 100644 */ VkPipeline getPipelineHandle( const DxvkGraphicsPipelineStateInfo& state, -- const DxvkRenderPass& renderPass); -+ const Rc<DxvkRenderPass>& renderPass, +- const DxvkRenderPass* renderPass); ++ const DxvkRenderPass* renderPass, + bool async); -- private: -+ VkPipeline compileInstance( -+ const Rc<DxvkGraphicsPipelineInstance>& instance, -+ const Rc<DxvkRenderPass>& renderPass); - -- struct PipelineStruct { -- DxvkGraphicsPipelineStateInfo stateVector; -- VkRenderPass renderPass; -- VkPipeline pipeline; -- }; -+ private: - - Rc<vk::DeviceFn> m_vkd; - DxvkPipelineManager* m_pipeMgr; -@@ -270,10 +291,10 @@ namespace dxvk { - DxvkGraphicsCommonPipelineStateInfo m_common; - - // List of pipeline instances, shared between threads -- alignas(CACHE_LINE_SIZE) sync::Spinlock m_mutex; -- std::vector<DxvkGraphicsPipelineInstance> m_pipelines; -+ alignas(CACHE_LINE_SIZE) sync::Spinlock m_mutex; -+ std::vector<Rc<DxvkGraphicsPipelineInstance>> m_pipelines; - -- const DxvkGraphicsPipelineInstance* findInstance( -+ DxvkGraphicsPipelineInstance* findInstance( - const DxvkGraphicsPipelineStateInfo& state, - VkRenderPass renderPass) const; - -@@ -301,4 +322,4 @@ namespace dxvk { - - }; - --} -\ No newline at end of file -+} + /** + * \brief Compiles a pipeline diff --git a/src/dxvk/dxvk_image.h b/src/dxvk/dxvk_image.h -index 1035a23d..209f4f06 100644 +index 8f82d65a..156f6054 100644 --- a/src/dxvk/dxvk_image.h +++ b/src/dxvk/dxvk_image.h -@@ -439,6 +439,37 @@ namespace dxvk { +@@ -442,6 +442,37 @@ namespace dxvk { return result; } @@ -393,7 +219,7 @@ index 1035a23d..209f4f06 100644 private: Rc<vk::DeviceFn> m_vkd; -@@ -447,6 +478,9 @@ namespace dxvk { +@@ -450,6 +481,9 @@ namespace dxvk { DxvkImageViewCreateInfo m_info; VkImageView m_views[ViewCount]; @@ -404,19 +230,19 @@ index 1035a23d..209f4f06 100644 }; diff --git a/src/dxvk/dxvk_options.cpp b/src/dxvk/dxvk_options.cpp -index f18fd70f..e051c06d 100644 +index 394feabb..df05ecd8 100644 --- a/src/dxvk/dxvk_options.cpp +++ b/src/dxvk/dxvk_options.cpp @@ -5,6 +5,7 @@ namespace dxvk { DxvkOptions::DxvkOptions(const Config& config) { enableStateCache = config.getOption<bool> ("dxvk.enableStateCache", true); - enableTransferQueue = config.getOption<bool> ("dxvk.enableTransferQueue", true); -+ useAsync = config.getOption<bool> ("dxvk.useAsync", false); + enableOpenVR = config.getOption<bool> ("dxvk.enableOpenVR", true); ++ useAsync = config.getOption<bool> ("dxvk.useAsync", true); numCompilerThreads = config.getOption<int32_t> ("dxvk.numCompilerThreads", 0); + asyncPresent = config.getOption<Tristate>("dxvk.asyncPresent", Tristate::Auto); useRawSsbo = config.getOption<Tristate>("dxvk.useRawSsbo", Tristate::Auto); - useEarlyDiscard = config.getOption<Tristate>("dxvk.useEarlyDiscard", Tristate::Auto); diff --git a/src/dxvk/dxvk_options.h b/src/dxvk/dxvk_options.h -index aec003e4..0fbb6dd0 100644 +index 447294b5..571d6c15 100644 --- a/src/dxvk/dxvk_options.h +++ b/src/dxvk/dxvk_options.h @@ -10,6 +10,7 @@ namespace dxvk { @@ -429,7 +255,7 @@ index aec003e4..0fbb6dd0 100644 bool enableTransferQueue; diff --git a/src/dxvk/dxvk_pipecompiler.cpp b/src/dxvk/dxvk_pipecompiler.cpp new file mode 100644 -index 00000000..a70c9908 +index 00000000..cfef228a --- /dev/null +++ b/src/dxvk/dxvk_pipecompiler.cpp @@ -0,0 +1,69 @@ @@ -468,11 +294,11 @@ index 00000000..a70c9908 + + + void DxvkPipelineCompiler::queueCompilation( -+ const Rc<DxvkGraphicsPipeline>& pipeline, -+ const Rc<DxvkGraphicsPipelineInstance>& instance, -+ const Rc<DxvkRenderPass>& renderPass) { ++ DxvkGraphicsPipeline* pipeline, ++ const DxvkGraphicsPipelineStateInfo& state, ++ const DxvkRenderPass* renderPass) { + std::unique_lock<std::mutex> lock(m_compilerLock); -+ m_compilerQueue.push({ pipeline, instance, renderPass }); ++ m_compilerQueue.push({ pipeline, state, renderPass }); + m_compilerCond.notify_one(); + } + @@ -496,15 +322,15 @@ index 00000000..a70c9908 + } + } + -+ if (entry.pipeline != nullptr && entry.instance != nullptr) -+ entry.pipeline->compileInstance(entry.instance, entry.renderPass); ++ if (entry.pipeline != nullptr && entry.renderPass != nullptr) ++ entry.pipeline->compilePipeline(entry.state, entry.renderPass); + } + } + +} diff --git a/src/dxvk/dxvk_pipecompiler.h b/src/dxvk/dxvk_pipecompiler.h new file mode 100644 -index 00000000..26e983cc +index 00000000..a82fff60 --- /dev/null +++ b/src/dxvk/dxvk_pipecompiler.h @@ -0,0 +1,60 @@ @@ -521,7 +347,7 @@ index 00000000..26e983cc +namespace dxvk { + + class DxvkGraphicsPipeline; -+ class DxvkGraphicsPipelineInstance; ++ class DxvkGraphicsPipelineStateInfo; + + /** + * \brief Pipeline compiler @@ -541,20 +367,20 @@ index 00000000..26e983cc + * This should be used to compile graphics + * pipeline instances asynchronously. + * \param [in] pipeline The pipeline object -+ * \param [in] instance The pipeline instance ++ * \param [in] state The pipeline state info object + * \param [in] renderPass + */ + void queueCompilation( -+ const Rc<DxvkGraphicsPipeline>& pipeline, -+ const Rc<DxvkGraphicsPipelineInstance>& instance, -+ const Rc<DxvkRenderPass>& renderPass); ++ DxvkGraphicsPipeline* pipeline, ++ const DxvkGraphicsPipelineStateInfo& state, ++ const DxvkRenderPass* renderPass); + + private: + + struct PipelineEntry { -+ Rc<DxvkGraphicsPipeline> pipeline; -+ Rc<DxvkGraphicsPipelineInstance> instance; -+ Rc<DxvkRenderPass> renderPass; ++ DxvkGraphicsPipeline* pipeline = nullptr; ++ DxvkGraphicsPipelineStateInfo state; ++ const DxvkRenderPass* renderPass = nullptr; + }; + + std::atomic<bool> m_compilerStop = { false }; @@ -569,7 +395,7 @@ index 00000000..26e983cc + +} diff --git a/src/dxvk/dxvk_pipemanager.cpp b/src/dxvk/dxvk_pipemanager.cpp -index 682db83d..cb7e993b 100644 +index 378bb3d1..3323f926 100644 --- a/src/dxvk/dxvk_pipemanager.cpp +++ b/src/dxvk/dxvk_pipemanager.cpp @@ -45,9 +45,13 @@ namespace dxvk { @@ -587,10 +413,10 @@ index 682db83d..cb7e993b 100644 diff --git a/src/dxvk/dxvk_pipemanager.h b/src/dxvk/dxvk_pipemanager.h -index fb62cb9a..c3b846cf 100644 +index f0087d15..29e758c7 100644 --- a/src/dxvk/dxvk_pipemanager.h +++ b/src/dxvk/dxvk_pipemanager.h -@@ -5,6 +5,7 @@ +@@ -6,6 +6,7 @@ #include "dxvk_compute.h" #include "dxvk_graphics.h" @@ -598,7 +424,7 @@ index fb62cb9a..c3b846cf 100644 namespace dxvk { -@@ -139,6 +140,7 @@ namespace dxvk { +@@ -107,6 +108,7 @@ namespace dxvk { const DxvkDevice* m_device; Rc<DxvkPipelineCache> m_cache; Rc<DxvkStateCache> m_stateCache; @@ -606,24 +432,11 @@ index fb62cb9a..c3b846cf 100644 std::atomic<uint32_t> m_numComputePipelines = { 0 }; std::atomic<uint32_t> m_numGraphicsPipelines = { 0 }; -diff --git a/src/dxvk/dxvk_state_cache.cpp b/src/dxvk/dxvk_state_cache.cpp -index a9249a3a..4d296c19 100644 ---- a/src/dxvk/dxvk_state_cache.cpp -+++ b/src/dxvk/dxvk_state_cache.cpp -@@ -263,7 +263,7 @@ namespace dxvk { - const auto& entry = m_entries[e->second]; - - auto rp = m_passManager->getRenderPass(entry.format); -- pipeline->getPipelineHandle(entry.gpState, *rp); -+ pipeline->getPipelineHandle(entry.gpState, rp, false); - } - } else { - auto pipeline = m_pipeManager->createComputePipeline(item.cs); diff --git a/src/dxvk/meson.build b/src/dxvk/meson.build -index 604434c2..bf90af2d 100644 +index 867f3002..f4c4336c 100644 --- a/src/dxvk/meson.build +++ b/src/dxvk/meson.build -@@ -77,6 +77,7 @@ dxvk_src = files([ +@@ -82,6 +82,7 @@ dxvk_src = files([ 'dxvk_openvr.cpp', 'dxvk_options.cpp', 'dxvk_pipecache.cpp', @@ -631,23 +444,3 @@ index 604434c2..bf90af2d 100644 'dxvk_pipelayout.cpp', 'dxvk_pipemanager.cpp', 'dxvk_queue.cpp', -diff --git a/dxvk.conf b/dxvk.conf -index 25d27cb9..4e409075 100644 ---- a/dxvk.conf -+++ b/dxvk.conf -@@ -159,6 +159,15 @@ - # dxvk.numCompilerThreads = 0 - - -+# Compile pipelines asynchronously if possible. This may reduce stuttering -+# in some games, but may also introduce rendering issues that might become -+# apparent over time. Do not report bugs with this option enabled. -+# -+# Supported values: True, False -+ -+# dxvk.useAsync = False -+ -+ - # Toggles raw SSBO usage. - # - # Uses storage buffers to implement raw and structured buffer diff --git a/dxvk-mangohud.patch b/dxvk-mangohud.patch new file mode 100644 index 000000000000..13fbdee8db9a --- /dev/null +++ b/dxvk-mangohud.patch @@ -0,0 +1,665 @@ +diff --git a/README.md b/README.md +index 25d03230..e8a53432 100644 +--- a/README.md ++++ b/README.md +@@ -1,3 +1,29 @@ ++# MangoHud Specific ++ ++- `DXVK_HUD_OFFSET_X` Set X offset of the DVXK Hud. ++- `DXVK_HUD_OFFSET_Y` Set Y offset of the DVXK Hud. ++- `DXVK_LOG_TO_FILE` Turn on logging and select path/filename (Fps,Cpu load,Gpu load) ++- Logging Gpu load requires either mangogpuload or gpuload hud options ++ ++# Hud options ++- `mangogpuload` : Shows current gpu load. ++- `mangocpuload` : Shows current cpu load. ++ ++# Keybinds ++- `F2` : Toggle Logging on/off ++- `F12` : Toggle Hud on/off ++ ++# MangoLog file ++ ++ When you press F2, a file is created with your chosen name + date/time stamp. ++ this file can be uploaded to https://flightlessmango.com/logs/new to create graphs automatically. ++ you can share the created page with others, just link it. ++ ++ #### Multiple log files ++ ++ It's possible to upload multiple files, you can rename them to your preferred names and upload them in a batch. ++ The graphs will then use those names in the data. ++ + # DXVK + + A Vulkan-based translation layer for Direct3D 10/11 which allows running 3D applications on Linux using Wine. +diff --git a/src/dxvk/dxvk_cpu.h b/src/dxvk/dxvk_cpu.h +new file mode 100644 +index 00000000..b2c8736a +--- /dev/null ++++ b/src/dxvk/dxvk_cpu.h +@@ -0,0 +1,172 @@ ++#include <cmath> ++#include <iomanip> ++#include <array> ++#include <vector> ++#include <algorithm> ++#include <iterator> ++#include <thread> ++#include <sstream> ++#include <fstream> ++using namespace std; ++ ++const int NUM_CPU_STATES = 10; ++ ++struct Cpus{ ++ size_t num; ++ string name; ++ float value; ++ string output; ++}; ++ ++size_t numCpuCores = dxvk::thread::hardware_concurrency(); ++size_t arraySize = numCpuCores + 1; ++std::vector<Cpus> cpuArray; ++ ++void coreCounting(){ ++ cpuArray.push_back({0, "CPU:"}); ++ for (size_t i = 0; i < arraySize; i++) { ++ size_t offset = i; ++ stringstream ss; ++ ss << "CPU" << offset << ":"; ++ string cpuNameString = ss.str(); ++ cpuArray.push_back({i+1 , cpuNameString}); ++ } ++} ++ ++std::string m_cpuUtilizationString; ++ ++enum CPUStates ++{ ++ S_USER = 0, ++ S_NICE, ++ S_SYSTEM, ++ S_IDLE, ++ S_IOWAIT, ++ S_IRQ, ++ S_SOFTIRQ, ++ S_STEAL, ++ S_GUEST, ++ S_GUEST_NICE ++}; ++ ++typedef struct CPUData ++{ ++ std::string cpu; ++ size_t times[NUM_CPU_STATES]; ++} CPUData; ++ ++void ReadStatsCPU(std::vector<CPUData> & entries) ++{ ++ std::ifstream fileStat("/proc/stat"); ++ ++ std::string line; ++ ++ const std::string STR_CPU("cpu"); ++ const std::size_t LEN_STR_CPU = STR_CPU.size(); ++ const std::string STR_TOT("tot"); ++ ++ while(std::getline(fileStat, line)) ++ { ++ // cpu stats line found ++ if(!line.compare(0, LEN_STR_CPU, STR_CPU)) ++ { ++ std::istringstream ss(line); ++ ++ // store entry ++ entries.emplace_back(CPUData()); ++ CPUData & entry = entries.back(); ++ ++ // read cpu label ++ ss >> entry.cpu; ++ ++ if(entry.cpu.size() > LEN_STR_CPU) ++ entry.cpu.erase(0, LEN_STR_CPU); ++ else ++ entry.cpu = STR_TOT; ++ ++ // read times ++ for(int i = 0; i < NUM_CPU_STATES; ++i) ++ ss >> entry.times[i]; ++ } ++ } ++} ++ ++size_t GetIdleTime(const CPUData & e) ++{ ++ return e.times[S_IDLE] + ++ e.times[S_IOWAIT]; ++} ++ ++size_t GetActiveTime(const CPUData & e) ++{ ++ return e.times[S_USER] + ++ e.times[S_NICE] + ++ e.times[S_SYSTEM] + ++ e.times[S_IRQ] + ++ e.times[S_SOFTIRQ] + ++ e.times[S_STEAL] + ++ e.times[S_GUEST] + ++ e.times[S_GUEST_NICE]; ++} ++ ++void PrintStats(const std::vector<CPUData> & entries1, const std::vector<CPUData> & entries2) ++{ ++ const size_t NUM_ENTRIES = entries1.size(); ++ ++ for(size_t i = 0; i < NUM_ENTRIES; ++i) ++ { ++ const CPUData & e1 = entries1[i]; ++ const CPUData & e2 = entries2[i]; ++ ++ const float ACTIVE_TIME = static_cast<float>(GetActiveTime(e2) - GetActiveTime(e1)); ++ const float IDLE_TIME = static_cast<float>(GetIdleTime(e2) - GetIdleTime(e1)); ++ const float TOTAL_TIME = ACTIVE_TIME + IDLE_TIME; ++ ++ cpuArray[i].value = (truncf(100.f * ACTIVE_TIME / TOTAL_TIME) * 10 / 10); ++ } ++} ++ ++int getCpuUsage() ++{ ++ std::vector<CPUData> entries1; ++ std::vector<CPUData> entries2; ++ ++ // snapshot 1 ++ ReadStatsCPU(entries1); ++ ++ // 100ms pause ++ std::this_thread::sleep_for(std::chrono::milliseconds(100)); ++ ++ // snapshot 2 ++ ReadStatsCPU(entries2); ++ ++ // print output ++ PrintStats(entries1, entries2); ++ ++ return 0; ++} ++ ++ ++void updateCpuStrings(){ ++ for (size_t i = 0; i < arraySize; i++) { ++ size_t spacing = 10; ++ string value = to_string(cpuArray[i].value); ++ value.erase( value.find_last_not_of('0') + 1, std::string::npos ); ++ size_t correctionValue = (spacing - cpuArray[i].name.length()) - value.length(); ++ string correction = ""; ++ for (size_t i = 0; i < correctionValue; i++) { ++ correction.append(" "); ++ } ++ stringstream ss; ++ if (i < 11) { ++ if (i == 0) { ++ ss << cpuArray[i].name << correction << cpuArray[i].value << "%"; ++ } else { ++ ss << cpuArray[i].name << correction << cpuArray[i].value << "%"; ++ } ++ } else { ++ ss << cpuArray[i].name << correction << cpuArray[i].value << "%"; ++ } ++ cpuArray[i].output = ss.str(); ++ } ++ } +\ No newline at end of file +diff --git a/src/dxvk/hud/dxvk_hud.cpp b/src/dxvk/hud/dxvk_hud.cpp +index 4fcd3bd2..b6e23c4c 100644 +--- a/src/dxvk/hud/dxvk_hud.cpp ++++ b/src/dxvk/hud/dxvk_hud.cpp +@@ -1,9 +1,13 @@ +-#include <cstring> + #include <version.h> +- + #include "dxvk_hud.h" ++#include <windows.h> ++#include <time.h> + + namespace dxvk::hud { ++ float Hud::offset_x_float = 0; ++ float Hud::offset_y_float = 0; ++ bool show_hud = true; ++ int lastPress; + + Hud::Hud( + const Rc<DxvkDevice>& device, +@@ -60,6 +64,14 @@ namespace dxvk::hud { + + Rc<Hud> Hud::createHud(const Rc<DxvkDevice>& device) { + std::string hudElements = env::getEnvVar("DXVK_HUD"); ++ std::string offset_x = env::getEnvVar("DXVK_HUD_OFFSET_X"); ++ std::string offset_y = env::getEnvVar("DXVK_HUD_OFFSET_Y"); ++ ++ if (!offset_x.empty()) ++ offset_x_float = stof(offset_x); ++ ++ if (!offset_y.empty()) ++ offset_y_float = stof(offset_y); + + if (hudElements.empty()) + hudElements = device->config().hud; +@@ -82,33 +94,45 @@ namespace dxvk::hud { + m_renderer.beginFrame(ctx, m_uniformData.surfaceSize); + } + +- + void Hud::renderHudElements(const Rc<DxvkContext>& ctx) { +- HudPos position = { 8.0f, 24.0f }; ++ if(GetAsyncKeyState(VK_F12) & 0x8000) ++ { ++ if (GetTickCount() - lastPress > 500){ ++ lastPress = GetTickCount(); ++ if (show_hud){ ++ show_hud = false; ++ } else { ++ show_hud = true; ++ } ++ } ++ } + +- if (m_config.elements.test(HudElement::DxvkVersion)) { +- m_renderer.drawText(ctx, 16.0f, +- { position.x, position.y }, +- { 1.0f, 1.0f, 1.0f, 1.0f }, +- "DXVK " DXVK_VERSION); +- position.y += 24.0f; +- } +- +- if (m_config.elements.test(HudElement::DxvkClientApi)) { +- m_renderer.drawText(ctx, 16.0f, +- { position.x, position.y }, +- { 1.0f, 1.0f, 1.0f, 1.0f }, +- m_device->clientApi()); +- position.y += 24.0f; +- } +- +- if (m_config.elements.test(HudElement::DeviceInfo)) { +- position = m_hudDeviceInfo.render( +- ctx, m_renderer, position); +- } ++ HudPos position = { offset_x_float + 8.0f, offset_y_float + 24.0f }; + +- position = m_hudFramerate.render(ctx, m_renderer, position); +- position = m_hudStats .render(ctx, m_renderer, position); ++ if (show_hud){ ++ if (m_config.elements.test(HudElement::DxvkVersion)) { ++ m_renderer.drawText(ctx, 16.0f, ++ { position.x, position.y }, ++ { 1.0f, 1.0f, 1.0f, 1.0f }, ++ "DXVK " DXVK_VERSION); ++ position.y += 24.0f; ++ } ++ ++ if (m_config.elements.test(HudElement::DxvkClientApi)) { ++ m_renderer.drawText(ctx, 16.0f, ++ { position.x, position.y }, ++ { 1.0f, 1.0f, 1.0f, 1.0f }, ++ m_device->clientApi()); ++ position.y += 24.0f; ++ } ++ ++ if (m_config.elements.test(HudElement::DeviceInfo)) { ++ position = m_hudDeviceInfo.render( ++ ctx, m_renderer, position); ++ } ++ position = m_hudFramerate.render(ctx, m_renderer, position); ++ position = m_hudStats .render(ctx, m_renderer, position); ++ } + } + + +diff --git a/src/dxvk/hud/dxvk_hud.h b/src/dxvk/hud/dxvk_hud.h +index 3b702c3b..71779977 100644 +--- a/src/dxvk/hud/dxvk_hud.h ++++ b/src/dxvk/hud/dxvk_hud.h +@@ -29,6 +29,8 @@ namespace dxvk::hud { + class Hud : public RcObject { + + public: ++ static float offset_x_float; ++ static float offset_y_float; + + Hud( + const Rc<DxvkDevice>& device, +diff --git a/src/dxvk/hud/dxvk_hud_config.cpp b/src/dxvk/hud/dxvk_hud_config.cpp +index fe1745bd..020a394b 100644 +--- a/src/dxvk/hud/dxvk_hud_config.cpp ++++ b/src/dxvk/hud/dxvk_hud_config.cpp +@@ -16,6 +16,9 @@ namespace dxvk::hud { + { "version", HudElement::DxvkVersion }, + { "api", HudElement::DxvkClientApi }, + { "compiler", HudElement::CompilerActivity }, ++ { "mangogpuload", HudElement::GpuLoad }, ++ { "mangocpuload", HudElement::CpuLoad }, ++ { "mangocpuload", HudElement::Logging }, + }}; + + +diff --git a/src/dxvk/hud/dxvk_hud_config.h b/src/dxvk/hud/dxvk_hud_config.h +index 05a1e4b6..5d571663 100644 +--- a/src/dxvk/hud/dxvk_hud_config.h ++++ b/src/dxvk/hud/dxvk_hud_config.h +@@ -22,6 +22,9 @@ namespace dxvk::hud { + DxvkVersion = 8, + DxvkClientApi = 9, + CompilerActivity = 10, ++ GpuLoad = 11, ++ CpuLoad = 12, ++ Logging = 13, + }; + + using HudElements = Flags<HudElement>; +diff --git a/src/dxvk/hud/dxvk_hud_fps.cpp b/src/dxvk/hud/dxvk_hud_fps.cpp +index f8cb6e7d..84eb2db6 100644 +--- a/src/dxvk/hud/dxvk_hud_fps.cpp ++++ b/src/dxvk/hud/dxvk_hud_fps.cpp +@@ -1,7 +1,22 @@ + #include "dxvk_hud_fps.h" ++#include "dxvk_hud_stats.h" ++#include "../dxvk_cpu.h" ++#include <time.h> + + #include <cmath> + #include <iomanip> ++using namespace std; ++time_t now_log = time(0); ++tm *log_time = localtime(&now_log); ++fstream f; ++ ++struct logData{ ++ float fps; ++ float cpu; ++ uint64_t gpu; ++}; ++ ++std::vector<logData> logArray; + + namespace dxvk::hud { + +@@ -9,8 +24,8 @@ namespace dxvk::hud { + : m_elements (elements), + m_fpsString ("FPS: "), + m_prevFpsUpdate(Clock::now()), +- m_prevFtgUpdate(Clock::now()) { +- ++ m_prevFtgUpdate(Clock::now()), ++ m_prevLogUpdate(Clock::now()) { + } + + +@@ -25,11 +40,48 @@ namespace dxvk::hud { + TimePoint now = Clock::now(); + TimeDiff elapsedFps = std::chrono::duration_cast<TimeDiff>(now - m_prevFpsUpdate); + TimeDiff elapsedFtg = std::chrono::duration_cast<TimeDiff>(now - m_prevFtgUpdate); ++ TimeDiff elapsedLog = std::chrono::duration_cast<TimeDiff>(now - m_prevLogUpdate); + m_prevFtgUpdate = now; ++ ++ if(GetAsyncKeyState(VK_F2) & 0x8000) ++ { ++ elapsedF2 = std::chrono::duration_cast<TimeDiff>(now - m_prevF2Press); ++ if (elapsedF2.count() > UpdateInterval || elapsedF2.count() == 0) { ++ if (mango_logging){ ++ m_prevF2Press = now; ++ mango_logging = false; ++ for (size_t i = 0; i < logArray.size(); i++) { ++ f << logArray[i].fps << "," << logArray[i].cpu << "," << logArray[i].gpu << endl; ++ } ++ f.close(); ++ logArray.clear(); ++ } else { ++ m_prevF2Press = now; ++ now_log = time(0); ++ log_time = localtime(&now_log); ++ mango_logging = true; ++ string date = to_string(log_time->tm_year + 1900) + "-" + to_string(1 + log_time->tm_mon) + "-" + to_string(log_time->tm_mday) + "_" + to_string(1 + log_time->tm_hour) + "-" + to_string(1 + log_time->tm_min) + "-" + to_string(1 + log_time->tm_sec); ++ f.open(logging + "_" + date, f.out | f.app); ++ } ++ } ++ } ++ ++ if (elapsedLog.count() >= LogUpdateInterval) { ++ fps = (10'000'000ll * m_frameCount) / elapsedFps.count(); ++ if (!logging.empty()){ ++ if (mango_logging){ ++ logArray.push_back({float(fps / 10 + (float(fps % 10) / 10)), cpuArray[0].value, gpuLoad}); ++ } ++ } ++ m_prevLogUpdate = now; ++ } + +- // Update FPS string + if (elapsedFps.count() >= UpdateInterval) { +- const int64_t fps = (10'000'000ll * m_frameCount) / elapsedFps.count(); ++ // Update FPS string ++ coreCounting(); ++ dxvk::thread([this] () { getCpuUsage();}); ++ updateCpuStrings(); ++ m_cpuUtilizationString = str::format(cpuArray[0].output); + m_fpsString = str::format("FPS: ", fps / 10, ".", fps % 10); + + m_prevFpsUpdate = now; +@@ -46,32 +98,81 @@ namespace dxvk::hud { + const Rc<DxvkContext>& context, + HudRenderer& renderer, + HudPos position) { ++ if (m_elements.test(HudElement::GpuLoad)) { ++ position = this->renderGpuText( ++ context, renderer, position); ++ } ++ if (m_elements.test(HudElement::CpuLoad)) { ++ position = this->renderCpuText( ++ context, renderer, position); ++ } + if (m_elements.test(HudElement::Framerate)) { + position = this->renderFpsText( + context, renderer, position); +- } ++ } + + if (m_elements.test(HudElement::Frametimes)) { + position = this->renderFrametimeGraph( + context, renderer, position); + } + ++ if (mango_logging && !logging.empty()) { ++ this->renderLogging(context, renderer, ++ { float(renderer.surfaceSize().width) - 250.0f, float(renderer.surfaceSize().height) - 20.0f }); ++ } ++ + return position; + } + + +- HudPos HudFps::renderFpsText( +- const Rc<DxvkContext>& context, +- HudRenderer& renderer, +- HudPos position) { ++ ++ HudPos HudFps::renderGpuText( ++ const Rc<DxvkContext>& context, ++ HudRenderer& renderer, ++ HudPos position) { ++ renderer.drawText(context, 16.0f, ++ { position.x, position.y }, ++ { 1.0f, 1.0f, 1.0f, 1.0f }, ++ m_gpuLoadString); ++ ++ return HudPos { position.x, position.y + 24 }; ++} ++ ++HudPos HudFps::renderCpuText( ++const Rc<DxvkContext>& context, ++ HudRenderer& renderer, ++ HudPos position) { ++renderer.drawText(context, 16.0f, ++ { position.x, position.y }, ++ { 1.0f, 1.0f, 1.0f, 1.0f }, ++ m_cpuUtilizationString); ++ ++return HudPos { position.x, position.y + 24 }; ++} ++ ++HudPos HudFps::renderFpsText( ++ const Rc<DxvkContext>& context, ++ HudRenderer& renderer, ++ HudPos position) { + renderer.drawText(context, 16.0f, + { position.x, position.y }, + { 1.0f, 1.0f, 1.0f, 1.0f }, + m_fpsString); ++ ++ return HudPos { position.x, position.y + 24 }; ++ } + +- return HudPos { position.x, position.y + 24 }; +- } +- ++ HudPos HudFps::renderLogging( ++ const Rc<DxvkContext>& context, ++ HudRenderer& renderer, ++ HudPos position) { ++ renderer.drawText(context, 16.0f, ++ { position.x, position.y }, ++ { 1.0f, 1.0f, 1.0f, 1.0f }, ++ "Currently Logging..."); ++ ++ return HudPos { position.x, position.y}; ++ } + + HudPos HudFps::renderFrametimeGraph( + const Rc<DxvkContext>& context, +diff --git a/src/dxvk/hud/dxvk_hud_fps.h b/src/dxvk/hud/dxvk_hud_fps.h +index c8c4b984..b1476889 100644 +--- a/src/dxvk/hud/dxvk_hud_fps.h ++++ b/src/dxvk/hud/dxvk_hud_fps.h +@@ -17,8 +17,9 @@ namespace dxvk::hud { + using TimeDiff = std::chrono::microseconds; + using TimePoint = typename Clock::time_point; + +- constexpr static uint32_t NumDataPoints = 300; +- constexpr static int64_t UpdateInterval = 500'000; ++ constexpr static uint32_t NumDataPoints = 300; ++ constexpr static int64_t UpdateInterval = 500'000; ++ constexpr static int64_t LogUpdateInterval = 100'000; + public: + + HudFps(HudElements elements); +@@ -36,23 +37,46 @@ namespace dxvk::hud { + const HudElements m_elements; + + std::string m_fpsString; ++ bool mango_logging = false; ++ time_t lastPress = time(0); ++ std::string logging = env::getEnvVar("DXVK_LOG_TO_FILE"); ++ int64_t fps; + + TimePoint m_prevFpsUpdate; + TimePoint m_prevFtgUpdate; ++ TimePoint m_prevLogUpdate; ++ TimePoint m_prevF2Press; ++ TimeDiff elapsedF2; + int64_t m_frameCount = 0; + + std::array<float, NumDataPoints> m_dataPoints = {}; + uint32_t m_dataPointId = 0; ++ ++ HudPos renderGpuText( ++ const Rc<DxvkContext>& context, ++ HudRenderer& renderer, ++ HudPos position); ++ ++ HudPos renderCpuText( ++ const Rc<DxvkContext>& context, ++ HudRenderer& renderer, ++ HudPos position); + + HudPos renderFpsText( + const Rc<DxvkContext>& context, + HudRenderer& renderer, + HudPos position); + ++ + HudPos renderFrametimeGraph( + const Rc<DxvkContext>& context, + HudRenderer& renderer, + HudPos position); ++ ++ HudPos renderLogging( ++ const Rc<DxvkContext>& context, ++ HudRenderer& renderer, ++ HudPos position); + + }; + +diff --git a/src/dxvk/hud/dxvk_hud_stats.cpp b/src/dxvk/hud/dxvk_hud_stats.cpp +index 995f186b..be8a5eb7 100644 +--- a/src/dxvk/hud/dxvk_hud_stats.cpp ++++ b/src/dxvk/hud/dxvk_hud_stats.cpp +@@ -1,5 +1,7 @@ + #include "dxvk_hud_stats.h" + ++std::string m_gpuLoadString = "GPU: "; ++uint64_t gpuLoad; + namespace dxvk::hud { + + HudStats::HudStats(HudElements elements) +@@ -24,7 +26,7 @@ namespace dxvk::hud { + + // GPU load is a bit more complex than that since + // we don't want to update this every frame +- if (m_elements.test(HudElement::StatGpuLoad)) ++ if (m_elements.test(HudElement::GpuLoad) || m_elements.test(HudElement::StatGpuLoad)) + this->updateGpuLoad(); + } + +@@ -70,8 +72,8 @@ namespace dxvk::hud { + uint64_t busyTicks = ticks > m_diffGpuIdleTicks + ? uint64_t(ticks - m_diffGpuIdleTicks) + : uint64_t(0); +- +- m_gpuLoadString = str::format("GPU: ", (100 * busyTicks) / ticks, "%"); ++ gpuLoad = 100 * busyTicks / ticks; ++ m_gpuLoadString = str::format("GPU: ", (100 * busyTicks) / ticks, "%"); + } + } + +@@ -224,7 +226,8 @@ namespace dxvk::hud { + HudElement::StatPipelines, + HudElement::StatMemory, + HudElement::StatGpuLoad, +- HudElement::CompilerActivity); ++ HudElement::CompilerActivity, ++ HudElement::GpuLoad); + } + + } +diff --git a/src/dxvk/hud/dxvk_hud_stats.h b/src/dxvk/hud/dxvk_hud_stats.h +index 227f600c..b7d740f1 100644 +--- a/src/dxvk/hud/dxvk_hud_stats.h ++++ b/src/dxvk/hud/dxvk_hud_stats.h +@@ -7,6 +7,8 @@ + #include "dxvk_hud_config.h" + #include "dxvk_hud_renderer.h" + ++extern std::string m_gpuLoadString; ++extern uint64_t gpuLoad; + namespace dxvk::hud { + + /** +@@ -44,8 +46,6 @@ namespace dxvk::hud { + uint64_t m_prevGpuIdleTicks = 0; + uint64_t m_diffGpuIdleTicks = 0; + +- std::string m_gpuLoadString = "GPU: "; +- + void updateGpuLoad(); + + HudPos printDrawCallStats( diff --git a/extraopts.patch b/extraopts.patch new file mode 100644 index 000000000000..43a8fd6d10ec --- /dev/null +++ b/extraopts.patch @@ -0,0 +1,70 @@ +diff --git a/build-win32.txt b/build-win32.txt +index 0865fc5e..b93a280f 100644 +--- a/build-win32.txt ++++ b/build-win32.txt +@@ -5,10 +5,10 @@ ar = 'i686-w64-mingw32-ar' + strip = 'i686-w64-mingw32-strip' + + [properties] +-c_args=['-msse', '-msse2'] +-cpp_args=['-msse', '-msse2'] +-c_link_args = ['-static', '-static-libgcc'] +-cpp_link_args = ['-static', '-static-libgcc', '-static-libstdc++'] ++c_args=['-msse', '-msse2', @CARGS@] ++cpp_args=['-msse', '-msse2', @CARGS@] ++c_link_args = ['-static', '-static-libgcc', @LDARGS@] ++cpp_link_args = ['-static', '-static-libgcc', '-static-libstdc++', @LDARGS@] + needs_exe_wrapper = true + + [host_machine] +diff --git a/build-win64.txt b/build-win64.txt +index 2a7fbee3..9e3bfc2e 100644 +--- a/build-win64.txt ++++ b/build-win64.txt +@@ -5,8 +5,10 @@ ar = 'x86_64-w64-mingw32-ar' + strip = 'x86_64-w64-mingw32-strip' + + [properties] +-c_link_args = ['-static', '-static-libgcc'] +-cpp_link_args = ['-static', '-static-libgcc', '-static-libstdc++'] ++c_args=[@CARGS@] ++cpp_args=[@CARGS@] ++c_link_args = ['-static', '-static-libgcc', @LDARGS@] ++cpp_link_args = ['-static', '-static-libgcc', '-static-libstdc++', @LDARGS@] + needs_exe_wrapper = true + + [host_machine] +diff --git a/build-wine32.txt b/build-wine32.txt +index ba8d34a8..ecec2eb4 100644 +--- a/build-wine32.txt ++++ b/build-wine32.txt +@@ -7,9 +7,9 @@ strip = 'strip' + [properties] + needs_exe_wrapper = true + +-c_args=['-m32', '-msse', '-msse2', '-fvisibility=hidden'] +-cpp_args=['-m32', '-msse', '-msse2', '-fvisibility=hidden', '-fvisibility-inlines-hidden', '-D__WIDL_objidl_generated_name_0000000C='] +-cpp_link_args=['-m32', '-mwindows'] ++c_args=['-m32', '-msse', '-msse2', '-fvisibility=hidden', @CARGS@] ++cpp_args=['-m32', '-msse', '-msse2', '-fvisibility=hidden', '-fvisibility-inlines-hidden', '-D__WIDL_objidl_generated_name_0000000C=', @CARGS@] ++cpp_link_args=['-m32', '-mwindows', @LDARGS@] + + [host_machine] + system = 'linux' +diff --git a/build-wine64.txt b/build-wine64.txt +index b3e028bb..fb9d98fd 100644 +--- a/build-wine64.txt ++++ b/build-wine64.txt +@@ -7,9 +7,9 @@ strip = 'strip' + [properties] + needs_exe_wrapper = true + +-c_args=['-m64', '-fvisibility=hidden'] +-cpp_args=['-m64', '-fvisibility=hidden', '-fvisibility-inlines-hidden', '-D__WIDL_objidl_generated_name_0000000C='] +-cpp_link_args=['-m64', '-mwindows'] ++c_args=['-m64', '-fvisibility=hidden', @CARGS@] ++cpp_args=['-m64', '-fvisibility=hidden', '-fvisibility-inlines-hidden', '-D__WIDL_objidl_generated_name_0000000C=', @CARGS@] ++cpp_link_args=['-m64', '-mwindows', @LDARGS@] + + [host_machine] + system = 'linux' |