diff options
author | Vincent Grande | 2020-10-04 13:07:04 -0400 |
---|---|---|
committer | Vincent Grande | 2020-10-04 13:07:04 -0400 |
commit | 08194766967ccc207551447f37e17ed1b219615e (patch) | |
tree | 899d454b5eb4002094a716e2fbbee4c08401b767 | |
download | aur-08194766967ccc207551447f37e17ed1b219615e.tar.gz |
initial upload
-rw-r--r-- | .SRCINFO | 46 | ||||
-rw-r--r-- | PKGBUILD | 113 | ||||
-rw-r--r-- | dxvk-async.patch | 501 | ||||
-rw-r--r-- | extraopts.patch | 36 |
4 files changed, 696 insertions, 0 deletions
diff --git a/.SRCINFO b/.SRCINFO new file mode 100644 index 000000000000..0d9e3fc20d1b --- /dev/null +++ b/.SRCINFO @@ -0,0 +1,46 @@ +pkgbase = dxvk-mingw-proton-ge-async-git + pkgdesc = A Vulkan-based compatibility layer for Direct3D 9/10/11 which allows running 3D applications on Linux using Wine. Windows DLL version) + pkgver = 1.5.r3.ga265af74 + pkgrel = 1 + url = https://github.com/doitsujin/dxvk + arch = x86_64 + license = zlib/libpng + makedepends = ninja + makedepends = meson>=0.43 + makedepends = glslang + makedepends = mingw-w64-gcc + makedepends = git + makedepends = wine + depends = vulkan-icd-loader + depends = wine>=4.0rc1 + depends = lib32-vulkan-icd-loader + provides = dxvk + provides = d9vk + provides = dxvk=1.5.r3.ga265af74 + conflicts = d9vk-mingw-git + conflicts = dxvk-mingw-git + conflicts = dxvk-mingw + conflicts = dxvk-winelib + conflicts = d9vk-bin + conflicts = d9vk-winelib-git + conflicts = dxvk-bin + conflicts = dxvk-git + conflicts = dxvk-wine32-git + conflicts = dxvk-wine64-git + conflicts = dxvk-win32-git + conflicts = dxvk-win64-git + conflicts = dxvk-winelib-git + options = !strip + options = !buildflags + options = staticlibs + source = git+https://github.com/doitsujin/dxvk.git + source = dxvk-async.patch + source = extraopts.patch + sha256sums = SKIP + sha256sums = SKIP + sha256sums = SKIP + +pkgname = dxvk-mingw-proton-ge-async-git + arch = x86_64 + conflicts = dxvk-bin + diff --git a/PKGBUILD b/PKGBUILD new file mode 100644 index 000000000000..ed4a7899b601 --- /dev/null +++ b/PKGBUILD @@ -0,0 +1,113 @@ +# Maintainer: Vincent Grande <shoober420@gmail.com> +# Contributor: loathingkernel <loathingkernel @at gmail .dot com> +# Contributor: AdriĆ Cereto i MassaguĆ© <ssorgatem at gmail.com> + +pkgname=('dxvk-mingw-proton-ge-async-git') +pkgver=1.5.r3.ga265af74 +pkgrel=1 +pkgdesc="A Vulkan-based compatibility layer for Direct3D 9/10/11 which allows running 3D applications on Linux using Wine. Windows DLL version)" +arch=('x86_64') +url="https://github.com/doitsujin/dxvk" +license=('zlib/libpng') +depends=('vulkan-icd-loader' 'wine>=4.0rc1' 'lib32-vulkan-icd-loader') +provides=("dxvk" "d9vk" "dxvk=$pkgver") +makedepends=('ninja' 'meson>=0.43' 'glslang' 'mingw-w64-gcc' 'git' 'wine') +conflicts=('d9vk-mingw-git' 'dxvk-mingw-git' 'dxvk-mingw' 'dxvk-winelib' 'd9vk-bin' 'd9vk-winelib-git' "dxvk-bin" "dxvk-git" "dxvk-wine32-git" "dxvk-wine64-git" "dxvk-win32-git" "dxvk-win64-git" "dxvk-winelib-git") +options=(!strip !buildflags staticlibs) +source=("git+https://github.com/doitsujin/dxvk.git" + "dxvk-async.patch" + "extraopts.patch") +sha256sums=("SKIP" + "SKIP" + "SKIP") + + +pkgver() { + cd dxvk + git describe --long --tags | sed 's/\([^-]*-g\)/r\1/;s/-/./g;s/v//g' +} + +prepare() { + cd dxvk + + # Uncomment to enable extra optimizations + # Patch crossfiles with extra optimizations from makepkg.conf + patch -p1 -i "$srcdir"/extraopts.patch + local dxvk_cflags="$CFLAGS" + local dxvk_ldflags="$LDFLAGS" + # 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 AVX (and AVX2 as a side-effect). + # Relevant Wine issues + # https://bugs.winehq.org/show_bug.cgi?id=45289 + # https://bugs.winehq.org/show_bug.cgi?id=43516 + dxvk_cflags+=" -mno-avx" + # Filter fstack-protector{ ,-all,-strong} flag for MingW. + # https://github.com/Joshua-Ashton/d9vk/issues/476 + #dxvk_cflags+=" -fno-stack-protector" + dxvk_cflags="${dxvk_cflags// -fstack-protector*([\-all|\-strong])/}" + # Adjust optimization level in meson arguments. This is ignored + # anyway because meson sets its own optimization level. + dxvk_cflags="${dxvk_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. + dxvk_cflags="${dxvk_cflags/ -fno-plt/}" + dxvk_ldflags="${dxvk_ldflags/,-z,now/}" + dxvk_ldflags="${dxvk_ldflags/,-z,relro/}" + sed -i build-win64.txt \ + -e "s|@CARGS@|\'${dxvk_cflags// /\',\'}\'|g" \ + -e "s|@LDARGS@|\'${dxvk_ldflags// /\',\'}\'|g" + sed -i build-win32.txt \ + -e "s|@CARGS@|\'${dxvk_cflags// /\',\'}\'|g" \ + -e "s|@LDARGS@|\'${dxvk_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 "$srcdir"/dxvk-async.patch +} + +build() { + meson dxvk "build/x64" \ + --cross-file dxvk/build-win64.txt \ + --prefix "/usr/share/dxvk/x64" \ + --bindir "" --libdir "" \ + --buildtype "release" \ + --strip \ + -D enable_tests=false + ninja -C "build/x64" + + meson dxvk "build/x32" \ + --cross-file dxvk/build-win32.txt \ + --prefix "/usr/share/dxvk/x32" \ + --bindir "" --libdir "" \ + --buildtype "release" \ + --strip \ + -D enable_tests=false + ninja -C "build/x32" +} + +package_dxvk-mingw-proton-ge-async-git() { + arch=('x86_64') + conflicts=("dxvk-bin") + 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" + 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" + + rm -rf /usr/share/steam/compatibilitytools.d/proton-ge-custom*/dist/lib/wine/dxvk/d3d* + rm -rf /usr/share/steam/compatibilitytools.d/proton-ge-custom*/dist/lib/wine/dxvk/dxg* + rm -rf /usr/share/steam/compatibilitytools.d/proton-ge-custom*/dist/lib64/wine/dxvk/d3d* + rm -rf /usr/share/steam/compatibilitytools.d/proton-ge-custom*/dust/lib64/wine/dxvk/dxg* + + ln -s /usr/share/dxvk/x32/* /usr/share/steam/compatibilitytools.d/proton-ge-custom*/dist/lib/wine/dxvk/ + + ln -s /usr/share/dxvk/x64/* /usr/share/steam/compatibilitytools.d/proton-ge-custom*/dist/lib64/wine/dxvk/ +} diff --git a/dxvk-async.patch b/dxvk-async.patch new file mode 100644 index 000000000000..d877be322826 --- /dev/null +++ b/dxvk-async.patch @@ -0,0 +1,501 @@ +diff --git a/meson.build b/meson.build +index 8fa3ce61..5e4d32d1 100644 +--- a/meson.build ++++ b/meson.build +@@ -103,7 +103,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 797c4e20..bda90275 100644 +--- a/src/dxvk/dxvk_context.cpp ++++ b/src/dxvk/dxvk_context.cpp +@@ -3837,7 +3837,9 @@ 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; +@@ -4093,7 +4095,7 @@ namespace dxvk { + } + + +- void DxvkContext::updateFramebuffer() { ++ void DxvkContext::updateFramebuffer(bool isDraw) { + if (m_flags.test(DxvkContextFlag::GpDirtyFramebuffer)) { + m_flags.clr(DxvkContextFlag::GpDirtyFramebuffer); + +@@ -4114,6 +4116,11 @@ namespace dxvk { + m_state.gp.state.omSwizzle[i] = DxvkOmAttachmentSwizzle(mapping); + } + ++ if (isDraw) { ++ for (uint32_t i = 0; i < fb->numAttachments(); i++) ++ fb->getAttachment(i).view->setRtBindingFrameId(m_device->getCurrentFrameId()); ++ } ++ + m_flags.set(DxvkContextFlag::GpDirtyPipelineState); + } + } +@@ -4343,7 +4350,7 @@ namespace dxvk { + } + + if (m_flags.test(DxvkContextFlag::GpDirtyFramebuffer)) +- this->updateFramebuffer(); ++ this->updateFramebuffer(true); + + if (!m_flags.test(DxvkContextFlag::GpRenderPassBound)) + this->startRenderPass(); +@@ -4772,6 +4779,14 @@ namespace dxvk { + } + } + ++ 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; ++ } + + DxvkGraphicsPipeline* DxvkContext::lookupGraphicsPipeline( + const DxvkGraphicsPipelineShaders& shaders) { +diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h +index 2456b20a..d58f1021 100644 +--- a/src/dxvk/dxvk_context.h ++++ b/src/dxvk/dxvk_context.h +@@ -1159,7 +1159,7 @@ namespace dxvk { + VkDescriptorSet set, + const DxvkPipelineLayout* layout); + +- void updateFramebuffer(); ++ void updateFramebuffer(bool isDraw = false); + + void updateIndexBufferBinding(); + void updateVertexBufferBindings(); +@@ -1211,6 +1211,8 @@ namespace dxvk { + + void trackDrawBuffer(); + ++ bool checkAsyncCompilationCompat(); ++ + DxvkGraphicsPipeline* lookupGraphicsPipeline( + const DxvkGraphicsPipelineShaders& shaders); + +diff --git a/src/dxvk/dxvk_graphics.cpp b/src/dxvk/dxvk_graphics.cpp +index 192e340b..96826600 100644 +--- a/src/dxvk/dxvk_graphics.cpp ++++ b/src/dxvk/dxvk_graphics.cpp +@@ -62,17 +62,21 @@ 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); ++ { //std::lock_guard<sync::Spinlock> lock(m_mutex); + + instance = this->findInstance(state, renderPass); + + 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) +@@ -83,13 +87,13 @@ namespace dxvk { + } + + +- void DxvkGraphicsPipeline::compilePipeline( ++ bool DxvkGraphicsPipeline::compilePipeline( + const DxvkGraphicsPipelineStateInfo& state, + const DxvkRenderPass* renderPass) { + std::lock_guard<sync::Spinlock> lock(m_mutex); + +- if (!this->findInstance(state, renderPass)) +- this->createInstance(state, renderPass); ++ return (this->findInstance(state, renderPass) == nullptr) && ++ (this->createInstance(state, renderPass) != nullptr); + } + + +@@ -103,6 +107,7 @@ namespace dxvk { + + VkPipeline newPipelineHandle = this->createPipeline(state, renderPass); + ++ std::lock_guard<sync::Spinlock> lock(m_mutex2); + m_pipeMgr->m_numGraphicsPipelines += 1; + return &m_pipelines.emplace_back(state, renderPass, newPipelineHandle); + } +@@ -111,6 +116,7 @@ namespace dxvk { + DxvkGraphicsPipelineInstance* DxvkGraphicsPipeline::findInstance( + const DxvkGraphicsPipelineStateInfo& state, + const DxvkRenderPass* renderPass) { ++ std::lock_guard<sync::Spinlock> lock(m_mutex2); + for (auto& instance : m_pipelines) { + if (instance.isCompatible(state, renderPass)) + return &instance; +diff --git a/src/dxvk/dxvk_graphics.h b/src/dxvk/dxvk_graphics.h +index 4194599d..c48ee3ed 100644 +--- a/src/dxvk/dxvk_graphics.h ++++ b/src/dxvk/dxvk_graphics.h +@@ -185,11 +185,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 +@@ -198,11 +200,16 @@ namespace dxvk { + * and stores the result for future use. + * \param [in] state Pipeline state vector + * \param [in] renderPass The render pass ++ * \returns \c true if compile succeeded + */ +- void compilePipeline( ++ bool compilePipeline( + const DxvkGraphicsPipelineStateInfo& state, + const DxvkRenderPass* renderPass); + ++ void writePipelineStateToCache( ++ const DxvkGraphicsPipelineStateInfo& state, ++ const DxvkRenderPassFormat& format) const; ++ + private: + + Rc<vk::DeviceFn> m_vkd; +@@ -221,6 +228,7 @@ namespace dxvk { + + // List of pipeline instances, shared between threads + alignas(CACHE_LINE_SIZE) sync::Spinlock m_mutex; ++ alignas(CACHE_LINE_SIZE) sync::Spinlock m_mutex2; + std::vector<DxvkGraphicsPipelineInstance> m_pipelines; + + DxvkGraphicsPipelineInstance* createInstance( +@@ -248,10 +256,6 @@ namespace dxvk { + bool validatePipelineState( + const DxvkGraphicsPipelineStateInfo& state) const; + +- void writePipelineStateToCache( +- const DxvkGraphicsPipelineStateInfo& state, +- const DxvkRenderPassFormat& format) const; +- + void logPipelineState( + LogLevel level, + const DxvkGraphicsPipelineStateInfo& state) const; +diff --git a/src/dxvk/dxvk_image.h b/src/dxvk/dxvk_image.h +index 19b5d85f..3da24c49 100644 +--- a/src/dxvk/dxvk_image.h ++++ b/src/dxvk/dxvk_image.h +@@ -465,6 +465,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; +@@ -473,6 +504,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 904082f6..999723cc 100644 +--- a/src/dxvk/dxvk_options.cpp ++++ b/src/dxvk/dxvk_options.cpp +@@ -3,8 +3,10 @@ + namespace dxvk { + + DxvkOptions::DxvkOptions(const Config& config) { ++ enableAsync = config.getOption<bool> ("dxvk.enableAsync", true); + enableStateCache = config.getOption<bool> ("dxvk.enableStateCache", true); + enableOpenVR = config.getOption<bool> ("dxvk.enableOpenVR", true); ++ numAsyncThreads = config.getOption<int32_t> ("dxvk.numAsyncThreads", 0); + numCompilerThreads = config.getOption<int32_t> ("dxvk.numCompilerThreads", 0); + 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 6843c16f..84e1933f 100644 +--- a/src/dxvk/dxvk_options.h ++++ b/src/dxvk/dxvk_options.h +@@ -8,12 +8,19 @@ namespace dxvk { + DxvkOptions() { } + DxvkOptions(const Config& config); + ++ // Enable async pipelines ++ bool enableAsync; ++ + /// Enable state cache + bool enableStateCache; + + /// Enables OpenVR loading + bool enableOpenVR; + ++ /// Number of compiler threads ++ /// when using async pipelines ++ int32_t numAsyncThreads; ++ + /// Number of compiler threads + /// when using the state cache + int32_t numCompilerThreads; +diff --git a/src/dxvk/dxvk_pipecompiler.cpp b/src/dxvk/dxvk_pipecompiler.cpp +new file mode 100644 +index 00000000..40218acd +--- /dev/null ++++ b/src/dxvk/dxvk_pipecompiler.cpp +@@ -0,0 +1,76 @@ ++#include "dxvk_device.h" ++#include "dxvk_graphics.h" ++#include "dxvk_pipecompiler.h" ++ ++namespace dxvk { ++ ++ DxvkPipelineCompiler::DxvkPipelineCompiler(const DxvkDevice* device) { ++ uint32_t numCpuCores = dxvk::thread::hardware_concurrency(); ++ uint32_t numWorkers = ((std::max(1u, numCpuCores) - 1) * 5) / 7; ++ ++ if (numWorkers < 1) numWorkers = 1; ++ if (numWorkers > 32) numWorkers = 32; ++ ++ if (device->config().numAsyncThreads > 0) ++ numWorkers = device->config().numAsyncThreads; ++ ++ Logger::info(str::format("DXVK: Using ", numWorkers, " async compiler threads")); ++ ++ // Start the compiler threads ++ m_compilerThreads.resize(numWorkers); ++ ++ for (uint32_t i = 0; i < numWorkers; i++) { ++ m_compilerThreads.at(i) = dxvk::thread( ++ [this] { this->runCompilerThread(); }); ++ } ++ } ++ ++ ++ DxvkPipelineCompiler::~DxvkPipelineCompiler() { ++ { std::lock_guard<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::lock_guard<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)) { ++ entry.pipeline->writePipelineStateToCache(entry.state, entry.renderPass->format()); ++ } ++ } ++ } ++ ++} +diff --git a/src/dxvk/dxvk_pipecompiler.h b/src/dxvk/dxvk_pipecompiler.h +new file mode 100644 +index 00000000..d7fcc2cf +--- /dev/null ++++ b/src/dxvk/dxvk_pipecompiler.h +@@ -0,0 +1,61 @@ ++#pragma once ++ ++#include <atomic> ++#include <condition_variable> ++#include <mutex> ++#include <queue> ++ ++#include "../util/thread.h" ++#include "dxvk_include.h" ++ ++namespace dxvk { ++ ++ class DxvkDevice; ++ class DxvkGraphicsPipeline; ++ class DxvkGraphicsPipelineStateInfo; ++ ++ /** ++ * \brief Pipeline compiler ++ * ++ * Asynchronous pipeline compiler ++ */ ++ class DxvkPipelineCompiler : public RcObject { ++ ++ public: ++ ++ DxvkPipelineCompiler(const DxvkDevice* device); ++ ~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 2e29202e..1e767381 100644 +--- a/src/dxvk/dxvk_pipemanager.cpp ++++ b/src/dxvk/dxvk_pipemanager.cpp +@@ -9,7 +9,11 @@ namespace dxvk { + DxvkRenderPassPool* passManager) + : m_device (device), + m_cache (new DxvkPipelineCache(device->vkd())) { ++ std::string useAsync = env::getEnvVar("DXVK_ASYNC"); + std::string useStateCache = env::getEnvVar("DXVK_STATE_CACHE"); ++ ++ if (useAsync == "1" || device->config().enableAsync) ++ m_compiler = new DxvkPipelineCompiler(device); + + if (useStateCache != "0" && device->config().enableStateCache) + m_stateCache = new DxvkStateCache(device, this, passManager); +diff --git a/src/dxvk/dxvk_pipemanager.h b/src/dxvk/dxvk_pipemanager.h +index 858928ca..4c12a4dc 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 { + +@@ -95,6 +96,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 1dc113c3..003fb1a7 100644 +--- a/src/dxvk/meson.build ++++ b/src/dxvk/meson.build +@@ -83,6 +83,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/extraopts.patch b/extraopts.patch new file mode 100644 index 000000000000..3faec7e35d55 --- /dev/null +++ b/extraopts.patch @@ -0,0 +1,36 @@ +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] |