diff options
author | Stelios Tsampas | 2019-12-16 19:51:22 +0200 |
---|---|---|
committer | Stelios Tsampas | 2019-12-16 19:51:22 +0200 |
commit | 6724cfc86102383af0a6b9b5c01951cb0ba06285 (patch) | |
tree | cfa981e2e4998564654b31d30f6131394954c7c1 | |
parent | 18d91a7251336929cbd9816eaf4f6deb24975dca (diff) | |
download | aur-6724cfc86102383af0a6b9b5c01951cb0ba06285.tar.gz |
Version 1.5. Merge with d9vk
-rw-r--r-- | .SRCINFO | 35 | ||||
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | PKGBUILD | 108 | ||||
-rw-r--r-- | dxvk-async.patch | 446 | ||||
-rw-r--r-- | dxvk-mangohud.patch | 665 | ||||
-rw-r--r-- | extraopts.patch | 70 | ||||
-rw-r--r-- | setup_dxvk | 2 |
7 files changed, 1283 insertions, 46 deletions
@@ -1,36 +1,33 @@ pkgbase = dxvk-winelib - pkgdesc = A Vulkan-based compatibility layer for Direct3D 10/11 which allows running 3D applications on Linux using Wine. Winelib version. - pkgver = 1.4.4 - pkgrel = 2 + pkgdesc = Vulkan-based implementation of D3D9, D3D10 and D3D11 for Linux / Wine, Winelib version + pkgver = 1.5 + pkgrel = 1 url = https://github.com/doitsujin/dxvk arch = x86_64 license = zlib/libpng makedepends = ninja - makedepends = meson + makedepends = meson>=0.43 makedepends = glslang makedepends = git makedepends = wine depends = vulkan-icd-loader depends = wine>=4.0rc1 depends = lib32-vulkan-icd-loader - provides = dxvk-bin - provides = dxvk-git - provides = dxvk-wine32-git - provides = dxvk-wine64-git - provides = dxvk-win32-git - provides = dxvk-win64-git - provides = dxvk-mingw-git - provides = dxvk-winelib-git + depends = bash provides = dxvk - conflicts = dxvk-git - conflicts = dxvk-wine32-git - conflicts = dxvk-wine64-git - conflicts = dxvk-win32-git - conflicts = dxvk-win64-git - conflicts = dxvk-winelib-git + provides = d9vk conflicts = dxvk - source = git+https://github.com/doitsujin/dxvk.git#tag=v1.4.4 + conflicts = d9vk + source = git+https://github.com/doitsujin/dxvk.git#tag=v1.5 + source = setup_dxvk + source = dxvk-async.patch + source = dxvk-mangohud.patch + source = extraopts.patch sha256sums = SKIP + sha256sums = b2413cabd8cca56e2d308ef5513edf1c7f909036ed2ccfeae17536a0e864dc96 + sha256sums = 6ff286091c20327e67252e1e6812830a42c990d1ee56541023eb217712209f3c + sha256sums = 2e335237623aaf006f8814fc9712f3a4be0d678cd0714879a3a4545f3bbf41ce + sha256sums = acde3a23166f79fa87ab090200be2aabaf16e5876ce19b8270ad1179bb0bc7a5 pkgname = dxvk-winelib diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 5ed2b9752c6b..000000000000 --- a/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -src -pkg -dxvk @@ -1,49 +1,109 @@ -# Maintainer: nikos fytilis n - fit [at] live [dot] com +# Maintainer: loathingkernel <loathingkernel @at gmail .dot com> +# Contributor: nikos fytilis n - fit [at] live [dot] com # Contributor: AdriĆ Cereto i MassaguĆ© <ssorgatem at gmail.com> -pkgbase=dxvk-winelib pkgname=dxvk-winelib -pkgver=1.4.4 -pkgrel=2 -pkgdesc="A Vulkan-based compatibility layer for Direct3D 10/11 which allows running 3D applications on Linux using Wine. Winelib version." +pkgver=1.5 +pkgrel=1 +pkgdesc='Vulkan-based implementation of D3D9, D3D10 and D3D11 for Linux / Wine, Winelib version' arch=('x86_64') url="https://github.com/doitsujin/dxvk" license=('zlib/libpng') -depends=('vulkan-icd-loader' 'wine>=4.0rc1' 'lib32-vulkan-icd-loader') -makedepends=('ninja' 'meson' 'glslang' 'git' 'wine') -provides=("dxvk-bin" "dxvk-git" "dxvk-wine32-git" "dxvk-wine64-git" "dxvk-win32-git" "dxvk-win64-git" "dxvk-mingw-git" "dxvk-winelib-git" "dxvk") -conflicts=("dxvk-git" "dxvk-wine32-git" "dxvk-wine64-git" "dxvk-win32-git" "dxvk-win64-git" "dxvk-winelib-git" "dxvk") +depends=('vulkan-icd-loader' 'wine>=4.0rc1' 'lib32-vulkan-icd-loader' 'bash') +makedepends=('ninja' 'meson>=0.43' 'glslang' 'git' 'wine') +provides=('dxvk' 'd9vk') +conflicts=('dxvk' 'd9vk') +source=( + "git+https://github.com/doitsujin/dxvk.git#tag=v$pkgver" + "setup_dxvk" + "dxvk-async.patch" + "dxvk-mangohud.patch" + "extraopts.patch" +) +sha256sums=( + "SKIP" + "b2413cabd8cca56e2d308ef5513edf1c7f909036ed2ccfeae17536a0e864dc96" + "6ff286091c20327e67252e1e6812830a42c990d1ee56541023eb217712209f3c" + "2e335237623aaf006f8814fc9712f3a4be0d678cd0714879a3a4545f3bbf41ce" + "acde3a23166f79fa87ab090200be2aabaf16e5876ce19b8270ad1179bb0bc7a5" +) -source=("git+https://github.com/doitsujin/dxvk.git#tag=v$pkgver") -sha256sums=("SKIP") +prepare() { + cd dxvk + # Uncomment to enable extra optimizations + # Patch crossfiles with extra optimizations from makepkg.conf + #patch -p1 -i ../extraopts.patch + # Filter known bad flags before applying optimizations + # 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" + # Filter fstack-protector flag for MingW. + # https://github.com/Joshua-Ashton/d9vk/issues/476 + #CFLAGS+=" -fno-stack-protector" + #CFLAGS="${CFLAGS// -fstack-protector+(-all|-strong)/}" + #CFLAGS="${CFLAGS// -fstack-protector+(?=[ ])/}" + # Adjust optimization level in meson arguments. This is ignored + # anyway because meson sets its own optimization level. + CFLAGS="${CFLAGS// -O+([0-3s]|fast)/}" + # 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,now/}" + sed -i build-wine64.txt \ + -e "s|@CARGS@|\'${CFLAGS// /\',\'}\'|g" \ + -e "s|@LDARGS@|\'${LDFLAGS// /\',\'}\'|g" + sed -i build-wine32.txt \ + -e "s|@CARGS@|\'${CFLAGS// /\',\'}\'|g" \ + -e "s|@LDARGS@|\'${LDFLAGS// /\',\'}\'|g" -build() { + # 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() { meson dxvk "build/x64" \ --cross-file dxvk/build-wine64.txt \ --prefix "/usr/share/dxvk/x64" \ --bindir "" --libdir "" \ --buildtype "release" \ + --optimization=3 \ --strip \ - -D enable_tests=false - ninja -C "build/x64" + -Denable_tests=false + ninja -C "build/x64" -v meson dxvk "build/x32" \ --cross-file dxvk/build-wine32.txt \ --prefix "/usr/share/dxvk/x32" \ --bindir "" --libdir "" \ --buildtype "release" \ + --optimization=3 \ --strip \ - -D enable_tests=false - ninja -C "build/x32" + -Denable_tests=false + ninja -C "build/x32" -v } -package_dxvk-winelib() { - DESTDIR="$pkgdir" ninja -C "build/x32" install - DESTDIR="$pkgdir" ninja -C "build/x64" install - install -Dm 644 dxvk/setup_dxvk.sh "$pkgdir/usr/share/dxvk/setup_dxvk.sh" - install -Dm 644 dxvk/LICENSE "$pkgdir/share/licenses/$pkgname/LICENSE" - mkdir -p "$pkgdir/usr/bin" - ln -s /usr/share/dxvk/setup_dxvk.sh "$pkgdir/usr/bin/setup_dxvk" - chmod +x "$pkgdir/usr/share/dxvk/setup_dxvk.sh" +package() { + DESTDIR="$pkgdir" ninja -C "build/x32" install + DESTDIR="$pkgdir" ninja -C "build/x64" install + install -Dm 755 -t "$pkgdir/usr/share/dxvk" dxvk/setup_dxvk.sh + install -Dm 644 -t "$pkgdir/usr/share/doc/dxvk" dxvk/dxvk.conf + install -Dm 644 -t "$pkgdir/usr/share/$pkgname" dxvk/LICENSE + install -Dm 755 -t "$pkgdir/usr/bin" setup_dxvk } diff --git a/dxvk-async.patch b/dxvk-async.patch new file mode 100644 index 000000000000..19c506c4964f --- /dev/null +++ b/dxvk-async.patch @@ -0,0 +1,446 @@ +From dfac76f528d0fc88ecbfe27ccb87483840828b9b Mon Sep 17 00:00:00 2001 +From: Tk-Glitch <ti3nou@gmail.com> +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 9a519e46..dea82ee1 100644 +--- a/meson.build ++++ b/meson.build +@@ -101,7 +101,7 @@ else + endif + + dxvk_version = vcs_tag( +- command: ['git', 'describe', '--dirty=+'], ++ command: ['git', 'describe', '--dirty=-async'], + input: 'version.h.in', + output: 'version.h') + +diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp +index b4f679fa..13c86d8f 100644 +--- a/src/dxvk/dxvk_context.cpp ++++ b/src/dxvk/dxvk_context.cpp +@@ -606,7 +606,7 @@ namespace dxvk { + const Rc<DxvkImageView>& imageView, + VkImageAspectFlags clearAspects, + VkClearValue clearValue) { +- this->updateFramebuffer(); ++ this->updateFramebuffer(false); + + // Prepare attachment ops + DxvkColorAttachmentOps colorOp; +@@ -2433,7 +2433,7 @@ namespace dxvk { + VkExtent3D extent, + VkImageAspectFlags aspect, + VkClearValue value) { +- this->updateFramebuffer(); ++ this->updateFramebuffer(false); + + // Find out if the render target view is currently bound, + // so that we can avoid spilling the render pass if it is. +@@ -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 { + } + + +- void DxvkContext::updateFramebuffer() { ++ void DxvkContext::updateFramebuffer(bool isDraw) { + if (m_flags.test(DxvkContextFlag::GpDirtyFramebuffer)) { + m_flags.clr(DxvkContextFlag::GpDirtyFramebuffer); + +@@ -3988,6 +3988,11 @@ namespace dxvk { + : VkComponentMapping(); + } + ++ if (isDraw) { ++ for (uint32_t i = 0; i < fb->numAttachments(); i++) ++ fb->getAttachment(i).view->setRtBindingFrameId(m_device->getCurrentFrameId()); ++ } ++ + m_flags.set(DxvkContextFlag::GpDirtyPipelineState); + } + } +@@ -4205,7 +4210,7 @@ namespace dxvk { + template<bool Indexed> + void DxvkContext::commitGraphicsState() { + if (m_flags.test(DxvkContextFlag::GpDirtyFramebuffer)) +- this->updateFramebuffer(); ++ this->updateFramebuffer(true); + + if (!m_flags.test(DxvkContextFlag::GpRenderPassBound)) + this->startRenderPass(); +@@ -4465,4 +4470,13 @@ namespace dxvk { + } + } + +-} +\ No newline at end of file ++ ++ bool DxvkContext::checkAsyncCompilationCompat() { ++ bool fbCompat = true; ++ for (uint32_t i = 0; fbCompat && i < m_state.om.framebuffer->numAttachments(); i++) { ++ const auto& attachment = m_state.om.framebuffer->getAttachment(i); ++ fbCompat &= attachment.view->getRtBindingAsyncCompilationCompat(); ++ } ++ return fbCompat; ++ } ++} +diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h +index f54f5321..0984d085 100644 +--- a/src/dxvk/dxvk_context.h ++++ b/src/dxvk/dxvk_context.h +@@ -1141,7 +1141,7 @@ namespace dxvk { + VkDescriptorSet set, + const DxvkPipelineLayout* layout); + +- void updateFramebuffer(); ++ void updateFramebuffer(bool isDraw); + + void updateIndexBufferBinding(); + void updateVertexBufferBindings(); +@@ -1180,6 +1180,7 @@ namespace dxvk { + + void trackDrawBuffer(); + ++ bool checkAsyncCompilationCompat(); + }; + +-} +\ No newline at end of file ++} +diff --git a/src/dxvk/dxvk_graphics.cpp b/src/dxvk/dxvk_graphics.cpp +index 5e05b425..8586c794 100644 +--- a/src/dxvk/dxvk_graphics.cpp ++++ b/src/dxvk/dxvk_graphics.cpp +@@ -75,8 +75,6 @@ namespace dxvk { + + + DxvkGraphicsPipeline::~DxvkGraphicsPipeline() { +- for (const auto& instance : m_pipelines) +- this->destroyPipeline(instance.pipeline()); + } + + +@@ -96,7 +94,8 @@ namespace dxvk { + + VkPipeline DxvkGraphicsPipeline::getPipelineHandle( + const DxvkGraphicsPipelineStateInfo& state, +- const DxvkRenderPass* renderPass) { ++ const DxvkRenderPass* renderPass, ++ bool async) { + DxvkGraphicsPipelineInstance* instance = nullptr; + + { std::lock_guard<sync::Spinlock> lock(m_mutex); +@@ -105,10 +104,13 @@ namespace dxvk { + + if (instance) + return instance->pipeline(); +- +- instance = this->createInstance(state, renderPass); ++ ++ if (async && m_pipeMgr->m_compiler != nullptr) ++ m_pipeMgr->m_compiler->queueCompilation(this, state, renderPass); ++ else ++ instance = this->createInstance(state, renderPass); + } +- ++ + if (!instance) + return VK_NULL_HANDLE; + +diff --git a/src/dxvk/dxvk_graphics.h b/src/dxvk/dxvk_graphics.h +index 168e9714..07f0883d 100644 +--- a/src/dxvk/dxvk_graphics.h ++++ b/src/dxvk/dxvk_graphics.h +@@ -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 ++ * \param [in] async Compile asynchronously + * \returns Pipeline handle + */ + VkPipeline getPipelineHandle( + const DxvkGraphicsPipelineStateInfo& state, +- const DxvkRenderPass* renderPass); ++ const DxvkRenderPass* renderPass, ++ bool async); + + /** + * \brief Compiles a pipeline +diff --git a/src/dxvk/dxvk_image.h b/src/dxvk/dxvk_image.h +index 8f82d65a..156f6054 100644 +--- a/src/dxvk/dxvk_image.h ++++ b/src/dxvk/dxvk_image.h +@@ -442,6 +442,37 @@ namespace dxvk { + return result; + } + ++ /** ++ * \brief Sets render target usage frame number ++ * ++ * The image view will track internally when ++ * it was last used as a render target. This ++ * info is used for async shader compilation. ++ * \param [in] frameId Frame number ++ */ ++ void setRtBindingFrameId(uint32_t frameId) { ++ if (frameId != m_rtBindingFrameId) { ++ if (frameId == m_rtBindingFrameId + 1) ++ m_rtBindingFrameCount += 1; ++ else ++ m_rtBindingFrameCount = 0; ++ ++ m_rtBindingFrameId = frameId; ++ } ++ } ++ ++ /** ++ * \brief Checks for async pipeline compatibility ++ * ++ * Asynchronous pipeline compilation may be enabled if the ++ * render target has been drawn to in the previous frames. ++ * \param [in] frameId Current frame ID ++ * \returns \c true if async compilation is supported ++ */ ++ bool getRtBindingAsyncCompilationCompat() const { ++ return m_rtBindingFrameCount >= 5; ++ } ++ + private: + + Rc<vk::DeviceFn> m_vkd; +@@ -450,6 +481,9 @@ namespace dxvk { + DxvkImageViewCreateInfo m_info; + VkImageView m_views[ViewCount]; + ++ uint32_t m_rtBindingFrameId = 0; ++ uint32_t m_rtBindingFrameCount = 0; ++ + void createView(VkImageViewType type, uint32_t numLayers); + + }; +diff --git a/src/dxvk/dxvk_options.cpp b/src/dxvk/dxvk_options.cpp +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); + 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); +diff --git a/src/dxvk/dxvk_options.h b/src/dxvk/dxvk_options.h +index 447294b5..571d6c15 100644 +--- a/src/dxvk/dxvk_options.h ++++ b/src/dxvk/dxvk_options.h +@@ -10,6 +10,7 @@ namespace dxvk { + + /// Enable state cache + bool enableStateCache; ++ bool useAsync; + + /// Use transfer queue if available + bool enableTransferQueue; +diff --git a/src/dxvk/dxvk_pipecompiler.cpp b/src/dxvk/dxvk_pipecompiler.cpp +new file mode 100644 +index 00000000..cfef228a +--- /dev/null ++++ b/src/dxvk/dxvk_pipecompiler.cpp +@@ -0,0 +1,69 @@ ++#include "dxvk_graphics.h" ++#include "dxvk_pipecompiler.h" ++ ++namespace dxvk { ++ ++ DxvkPipelineCompiler::DxvkPipelineCompiler() { ++ uint32_t sysCpuCount = dxvk::thread::hardware_concurrency(); ++ uint32_t threadCount = sysCpuCount > 2 ? sysCpuCount - 2 : 1; ++ ++ Logger::info(str::format( ++ "DxvkPipelineCompiler: Using ", ++ threadCount, " workers")); ++ ++ // Start the compiler threads ++ m_compilerThreads.resize(threadCount); ++ ++ for (uint32_t i = 0; i < threadCount; i++) { ++ m_compilerThreads.at(i) = dxvk::thread( ++ [this] { this->runCompilerThread(); }); ++ } ++ } ++ ++ ++ DxvkPipelineCompiler::~DxvkPipelineCompiler() { ++ { std::unique_lock<std::mutex> lock(m_compilerLock); ++ m_compilerStop.store(true); ++ } ++ ++ m_compilerCond.notify_all(); ++ for (auto& thread : m_compilerThreads) ++ thread.join(); ++ } ++ ++ ++ void DxvkPipelineCompiler::queueCompilation( ++ DxvkGraphicsPipeline* pipeline, ++ const DxvkGraphicsPipelineStateInfo& state, ++ const DxvkRenderPass* renderPass) { ++ std::unique_lock<std::mutex> lock(m_compilerLock); ++ m_compilerQueue.push({ pipeline, state, renderPass }); ++ m_compilerCond.notify_one(); ++ } ++ ++ ++ void DxvkPipelineCompiler::runCompilerThread() { ++ env::setThreadName("dxvk-pcompiler"); ++ ++ while (!m_compilerStop.load()) { ++ PipelineEntry entry; ++ ++ { std::unique_lock<std::mutex> lock(m_compilerLock); ++ ++ m_compilerCond.wait(lock, [this] { ++ return m_compilerStop.load() ++ || m_compilerQueue.size() != 0; ++ }); ++ ++ if (m_compilerQueue.size() != 0) { ++ entry = std::move(m_compilerQueue.front()); ++ m_compilerQueue.pop(); ++ } ++ } ++ ++ 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..a82fff60 +--- /dev/null ++++ b/src/dxvk/dxvk_pipecompiler.h +@@ -0,0 +1,60 @@ ++#pragma once ++ ++#include <atomic> ++#include <condition_variable> ++#include <mutex> ++#include <queue> ++ ++#include "../util/thread.h" ++#include "dxvk_include.h" ++ ++namespace dxvk { ++ ++ class DxvkGraphicsPipeline; ++ class DxvkGraphicsPipelineStateInfo; ++ ++ /** ++ * \brief Pipeline compiler ++ * ++ * Asynchronous pipeline compiler ++ */ ++ class DxvkPipelineCompiler : public RcObject { ++ ++ public: ++ ++ DxvkPipelineCompiler(); ++ ~DxvkPipelineCompiler(); ++ ++ /** ++ * \brief Compiles a pipeline asynchronously ++ * ++ * This should be used to compile graphics ++ * pipeline instances asynchronously. ++ * \param [in] pipeline The pipeline object ++ * \param [in] state The pipeline state info object ++ * \param [in] renderPass ++ */ ++ void queueCompilation( ++ DxvkGraphicsPipeline* pipeline, ++ const DxvkGraphicsPipelineStateInfo& state, ++ const DxvkRenderPass* renderPass); ++ ++ private: ++ ++ struct PipelineEntry { ++ DxvkGraphicsPipeline* pipeline = nullptr; ++ DxvkGraphicsPipelineStateInfo state; ++ const DxvkRenderPass* renderPass = nullptr; ++ }; ++ ++ std::atomic<bool> m_compilerStop = { false }; ++ std::mutex m_compilerLock; ++ std::condition_variable m_compilerCond; ++ std::queue<PipelineEntry> m_compilerQueue; ++ std::vector<dxvk::thread> m_compilerThreads; ++ ++ void runCompilerThread(); ++ ++ }; ++ ++} +diff --git a/src/dxvk/dxvk_pipemanager.cpp b/src/dxvk/dxvk_pipemanager.cpp +index 378bb3d1..3323f926 100644 +--- a/src/dxvk/dxvk_pipemanager.cpp ++++ b/src/dxvk/dxvk_pipemanager.cpp +@@ -45,9 +45,13 @@ namespace dxvk { + : m_device (device), + m_cache (new DxvkPipelineCache(device->vkd())) { + std::string useStateCache = env::getEnvVar("DXVK_STATE_CACHE"); ++ std::string useAsync = env::getEnvVar("DXVK_ASYNC"); + + if (useStateCache != "0" && device->config().enableStateCache) + m_stateCache = new DxvkStateCache(device, this, passManager); ++ ++ if (useAsync != "0" || device->config().useAsync) ++ m_compiler = new DxvkPipelineCompiler(); + } + + +diff --git a/src/dxvk/dxvk_pipemanager.h b/src/dxvk/dxvk_pipemanager.h +index f0087d15..29e758c7 100644 +--- a/src/dxvk/dxvk_pipemanager.h ++++ b/src/dxvk/dxvk_pipemanager.h +@@ -6,6 +6,7 @@ + + #include "dxvk_compute.h" + #include "dxvk_graphics.h" ++#include "dxvk_pipecompiler.h" + + namespace dxvk { + +@@ -107,6 +108,7 @@ namespace dxvk { + const DxvkDevice* m_device; + Rc<DxvkPipelineCache> m_cache; + Rc<DxvkStateCache> m_stateCache; ++ Rc<DxvkPipelineCompiler> m_compiler; + + std::atomic<uint32_t> m_numComputePipelines = { 0 }; + std::atomic<uint32_t> m_numGraphicsPipelines = { 0 }; +diff --git a/src/dxvk/meson.build b/src/dxvk/meson.build +index 867f3002..f4c4336c 100644 +--- a/src/dxvk/meson.build ++++ b/src/dxvk/meson.build +@@ -82,6 +82,7 @@ dxvk_src = files([ + 'dxvk_openvr.cpp', + 'dxvk_options.cpp', + 'dxvk_pipecache.cpp', ++ 'dxvk_pipecompiler.cpp', + 'dxvk_pipelayout.cpp', + 'dxvk_pipemanager.cpp', + 'dxvk_queue.cpp', 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' diff --git a/setup_dxvk b/setup_dxvk new file mode 100644 index 000000000000..01a7b908b232 --- /dev/null +++ b/setup_dxvk @@ -0,0 +1,2 @@ +#!/bin/sh +/usr/share/dxvk/setup_dxvk.sh $1 --symlink |