Import pinned DXVK recipe prerequisite from PowerVR PR570

Copy only the standalone build recipe, source pin, BC-format prerequisite
and presentation-sync patch/check from wallentx/DroidDeck at d0f7264ea8.
Source: https://github.com/Droid-Deck/DroidDeck/pull/570
Preserve that proposal attribution; no Android app, compositor, managed
pack, private data or fork development history is imported.
This commit is contained in:
Leask Wong committed 2026-10-11 22:34:06 -04:00
1 parent de1a734fb5
commit f08eedb3f6
5 files changed
+227

No files matched your search

+31
View File
@@ -0,0 +1,31 @@
#!/usr/bin/env bash
# CI component build; this does not change the APK or an installed Proton depot.
set -euo pipefail
root=$(cd "$(dirname "$0")/../.." && pwd)
. "$root/tools/dxvk/source.env"
mkdir -p "${1:?output directory required}"
out=$(cd "$1" && pwd)
work=$(mktemp -d)
trap 'rm -rf "$work"' EXIT
git init -q "$work/source"
git -C "$work/source" fetch --depth=1 https://github.com/doitsujin/dxvk.git "$DXVK_REVISION"
git -C "$work/source" checkout -q --detach FETCH_HEAD
test "$(git -C "$work/source" rev-parse HEAD)" = "$DXVK_REVISION"
git -C "$work/source" submodule update --init --recursive --depth=1
for patch in "$root"/tools/dxvk/patches/*.patch; do
git -C "$work/source" apply --check "$patch"
git -C "$work/source" apply "$patch"
done
python3 "$root/tools/dxvk/check_present_sync.py" "$work/source/src/dxvk/dxvk_presenter.cpp"
for arch in 32 64; do
meson setup "$work/build$arch" "$work/source" --cross-file "$work/source/build-win$arch.txt" \
--buildtype release --prefix "$out" --bindir "x$arch" --libdir "x$arch" -Db_ndebug=if-release --strip
meson compile -C "$work/build$arch" -j 4
meson install -C "$work/build$arch"
done
cp "$work/source/LICENSE" "$out/LICENSE"
printf '%s\n' "$DXVK_REVISION" > "$out/source-commit"
git -C "$work/source" submodule status --recursive > "$out/submodules.txt"
git -C "$work/source" diff > "$out/downstream.patch"
tar --exclude-vcs --zstd -cf "$out/source.tar.zst" -C "$work/source" .
(cd "$out" && find x32 x64 -name '*.dll' -type f -print0 | sort -z | xargs -0 sha256sum > SHA256SUMS)
+116
View File
@@ -0,0 +1,116 @@
#!/usr/bin/env python3
"""Replay asynchronous WSI ownership using the pinned presenter's actual selections.
This checks semaphore selection, not the full Vulkan presenter. Real Vulkan
validation and device testing remain separate gates. Requires a native C++ compiler.
"""
import argparse
import os
from pathlib import Path
import re
import subprocess
import tempfile
def selection_code(source):
match = re.search(
r"// Return relevant Vulkan objects for the acquired image\s*"
r"(?P<acquire>.*?)\s*m_presentPending = true;", source, re.S)
wait = re.search(r"info\.pWaitSemaphores\s*=.*?;", source, re.S)
if not match or not wait:
raise ValueError("unsupported pinned presenter layout")
return match["acquire"], wait[0]
HARNESS = r'''
#include <array>
#include <cstdint>
#include <cstdio>
#include <vector>
using VkSemaphore = uint64_t;
struct Sync { VkSemaphore acquire, present; };
struct Info { const VkSemaphore* pWaitSemaphores; };
struct Presenter {
std::vector<Sync> m_semaphores;
std::vector<unsigned> m_images = {0, 1, 2, 3};
unsigned m_frameIndex = 0, m_imageIndex = 0;
bool m_hasSwapchainMaintenance1;
explicit Presenter(bool maintenance): m_hasSwapchainMaintenance1(maintenance) {
for (unsigned i = 0; i < (maintenance ? 4u : 8u); ++i)
m_semaphores.push_back({100 + i, 1 + i});
}
Sync acquire() {
Sync sync{}; unsigned image;
ACQUIRE_SELECTION
(void)image;
return sync;
}
VkSemaphore present() {
auto& currSync = m_semaphores.at(m_frameIndex);
Info info{};
PRESENT_SELECTION
return *info.pWaitSemaphores;
}
};
int replay(bool maintenance) {
Presenter p(maintenance);
std::array<VkSemaphore, 4> outstandingByImage{};
std::array<VkSemaphore, 4> outstandingByFence{};
// Deliberately delay reacquisition of image 2 beyond a full frame-ring cycle.
const std::array<unsigned, 21> imageOrder = {
2,0,3,0,1,3,0,1,1,2,3,1,0,3,2,2,0,1,3,0,2
};
for (unsigned iteration = 0; iteration < 200; ++iteration) {
p.m_imageIndex = imageOrder[iteration % imageOrder.size()];
if (maintenance) {
// The existing fence path waits this frame's previous present fence.
const auto completed = outstandingByFence.at(p.m_frameIndex);
for (auto& pending : outstandingByImage)
if (pending == completed) pending = 0;
}
// Acquisition and its GPU wait complete the last present of THIS image.
outstandingByImage.at(p.m_imageIndex) = 0;
const auto signal = p.acquire().present;
const auto wait = p.present();
if (signal != wait) {
std::fprintf(stderr, "FAIL: render signal differs from present wait\n");
return 2;
}
for (auto pending : outstandingByImage) {
if (pending == signal) {
std::fprintf(stderr, "FAIL: semaphore reused before presentation completion at frame %u\n", iteration);
return 2;
}
}
outstandingByImage.at(p.m_imageIndex) = signal;
if (maintenance) outstandingByFence.at(p.m_frameIndex) = signal;
p.m_frameIndex = (p.m_frameIndex + 1) % p.m_semaphores.size();
}
std::printf("PASS: %s, 200 out-of-order acquisitions\n", maintenance ? "present-fence path" : "no-present-fence path");
return 0;
}
int main() {
if (int status = replay(false)) return status;
return replay(true);
}
'''
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("source", type=Path, help="pinned dxvk_presenter.cpp, after patching")
args = parser.parse_args()
acquire, present = selection_code(args.source.read_text())
code = HARNESS.replace("ACQUIRE_SELECTION", acquire).replace("PRESENT_SELECTION", present)
with tempfile.TemporaryDirectory(prefix="dxvk-present-sync-") as directory:
cpp = Path(directory) / "replay.cpp"
exe = Path(directory) / "replay"
cpp.write_text(code)
subprocess.run([os.environ.get("HOST_CXX", "c++"), "-std=c++17", "-Wall", "-Wextra", str(cpp), "-o", str(exe)], check=True)
return subprocess.run([str(exe)]).returncode
if __name__ == "__main__":
raise SystemExit(main())
@@ -0,0 +1,53 @@
diff --git a/src/dxvk/dxvk_device_info.cpp b/src/dxvk/dxvk_device_info.cpp
index db09fba..8e9a76e 100644
--- a/src/dxvk/dxvk_device_info.cpp
+++ b/src/dxvk/dxvk_device_info.cpp
@@ -118,6 +118,17 @@ namespace dxvk {
initQueueProperties(instance, adapter, deviceInfo);
initMemoryProperties(instance, adapter);
+ m_hasBcFormats = true;
+ for (uint32_t value = VK_FORMAT_BC1_RGBA_UNORM_BLOCK; value <= VK_FORMAT_BC7_SRGB_BLOCK; value++) {
+ VkFormatProperties properties = { };
+ vk->vkGetPhysicalDeviceFormatProperties(adapter, VkFormat(value), &properties);
+ constexpr VkFormatFeatureFlags required = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT
+ | VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT
+ | VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT;
+ if ((properties.optimalTilingFeatures & required) != required)
+ m_hasBcFormats = false;
+ }
+
disableUnusedFeatures(instance, safeMode);
enableFeaturesAndExtensions();
@@ -785,6 +796,9 @@ namespace dxvk {
}
}
+ if (!m_hasBcFormats)
+ return std::string("Device does not support the BC formats required by Direct3D");
+
if (!m_featuresEnabled.extDescriptorHeap.descriptorHeap && m_properties.core.properties.limits.maxPushConstantsSize < MaxTotalPushDataSize)
return str::format("Device does not support ", MaxTotalPushDataSize, " of push data");
@@ -886,7 +900,7 @@ namespace dxvk {
ENABLE_FEATURE(core.features, shaderResourceResidency, false),
ENABLE_FEATURE(core.features, shaderResourceMinLod, false),
ENABLE_FEATURE(core.features, tessellationShader, false),
- ENABLE_FEATURE(core.features, textureCompressionBC, true),
+ ENABLE_FEATURE(core.features, textureCompressionBC, false),
ENABLE_FEATURE(core.features, variableMultisampleRate, false),
ENABLE_FEATURE(core.features, vertexPipelineStoresAndAtomics, false),
ENABLE_FEATURE(core.features, wideLines, false),
diff --git a/src/dxvk/dxvk_device_info.h b/src/dxvk/dxvk_device_info.h
index 0a55f90..8bbc770 100644
--- a/src/dxvk/dxvk_device_info.h
+++ b/src/dxvk/dxvk_device_info.h
@@ -394,6 +394,7 @@ namespace dxvk {
DxvkDeviceQueueMapping m_queueMapping = { };
+ bool m_hasBcFormats = false;
bool m_hasMeshShader = false;
bool m_hasFmask = false;
@@ -0,0 +1,26 @@
diff --git a/src/dxvk/dxvk_presenter.cpp b/src/dxvk/dxvk_presenter.cpp
index 643f7c5..4dc8c4d 100644
--- a/src/dxvk/dxvk_presenter.cpp
+++ b/src/dxvk/dxvk_presenter.cpp
@@ -161,6 +161,10 @@ namespace dxvk {
// Return relevant Vulkan objects for the acquired image
sync = m_semaphores.at(m_frameIndex);
+ // Without a present fence, reacquiring this image is the only guarantee
+ // that its previous presentation has consumed the wait semaphore.
+ if (!m_hasSwapchainMaintenance1)
+ sync.present = m_semaphores.at(m_imageIndex).present;
image = m_images.at(m_imageIndex);
m_presentPending = true;
@@ -239,7 +243,9 @@ namespace dxvk {
VkPresentInfoKHR info = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
info.waitSemaphoreCount = 1;
- info.pWaitSemaphores = &currSync.present;
+ info.pWaitSemaphores = m_hasSwapchainMaintenance1
+ ? &currSync.present
+ : &m_semaphores.at(m_imageIndex).present;
info.swapchainCount = 1;
info.pSwapchains = &m_swapchain;
info.pImageIndices = &m_imageIndex;
+1
View File
@@ -0,0 +1 @@
DXVK_REVISION=25ca63f17f34bdc05a39873ee63907d3cbbfa030