Files
iChris4andClaude Opus 5.5 cc653272c8 Added foveated rendering for the Quest
- Eyes render under a VK_EXT_fragment_density_map: full rate around each eye's forward direction,
  2x2 then 4x4 pixel blocks towards the edges ([vr] foveation = off|low|medium|high, default off).
  XR_FB_foveation cannot help here: the runtime's maps only shape passes drawing into its
  swapchain, and the eyes reach it through a copy.
- aurora-main/patches/dawn/aurora_fdm.inc: Dawn enables the extension only on request and for
  dynamic rendering, flags every render pipeline, and chains an immutable RG8 map into any pass
  whose first color attachment is a view bound to one (ABI: include/aurora/dawn_fdm_abi.h).
- android/Build-QuestDawn.ps1 builds the pinned Dawn revision with those patches for arm64
  (dawn-build CI flags, protobuf off) into a cached package; Build-Quest.ps1 links it
  (-StockDawn opts out) and AuroraDawnProvider.cmake enables the ABI from its manifest.
- lib/gfx/foveation.hpp generates the maps (32 px per texel, densities 255/127/63); an eye is
  foveated only when single_pass_eyes draws it in one render pass. Menus never are.
- Live level from the headset panel's VR tab and the launcher; the launch decides whether the
  device has maps. debug.wiicompiled.foveation and debug.wiicompiled.fdm for A/B.
- Tests: Foveation cases in gx_fifo_tests, mkw_vr_config_tests. Docs: OPENXR.md, quest-port.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 19:03:17 +02:00

156 lines
8.1 KiB
Python

"""Apply Aurora's native Dawn patches to the pinned Dawn source tree.
- The versioned native Vulkan ABI (aurora_vulkan_interop.inc): the OpenXR runtime creates Dawn's
Vulkan instance and device, used by the Windows Vulkan OpenXR binding.
- Fragment density maps (aurora_fdm.inc): VK_EXT_fragment_density_map on Aurora's immersive eye
render passes, used by the Quest build.
Every edit is anchored on Dawn source text, asserts that the anchor exists, and is skipped when it
is already applied, so the script can run again on a patched tree.
"""
from pathlib import Path
import shutil, sys
root = Path(sys.argv[1]).resolve()
here = Path(__file__).resolve().parent
vulkan = root / "src/dawn/native/vulkan"
include = here.parent.parent / "include/aurora"
def read(path):
with open(path, encoding="utf-8", newline="") as f:
return f.read()
def write(path, text):
with open(path, "w", encoding="utf-8", newline="") as f:
f.write(text)
def insert(path, anchor, text, after=True):
"""Insert `text` after (or before) the one occurrence of `anchor` unless it is already there."""
s = read(path)
if text in s:
return
assert s.count(anchor) == 1, f"{path.name}: expected one occurrence of {anchor!r}"
s = s.replace(anchor, anchor + text if after else text + anchor, 1)
write(path, s)
for name in ("aurora_vulkan_hooks.h", "aurora_vulkan_interop.inc", "aurora_fdm.h", "aurora_fdm.inc"):
shutil.copyfile(here / name, vulkan / name)
shutil.copyfile(include / "dawn_vulkan_abi.h", vulkan / "aurora_dawn_vulkan_abi.h")
shutil.copyfile(include / "dawn_fdm_abi.h", vulkan / "aurora_dawn_fdm_abi.h")
p = vulkan / "VulkanBackend.cpp"
s = p.read_text()
if '#include "aurora_vulkan_interop.inc"' not in s:
s += '\n#include "aurora_vulkan_interop.inc"\n'
p.write_text(s)
p = root / "src/dawn/common/DynamicLib.cpp"
s = p.read_text()
# LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR requires an absolute filename. Vulkan's
# system loader is also tried by bare name; preserve the restricted default
# search directories for that case instead of failing with ERROR_INVALID_PARAMETER.
old = 'LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS;'
new = '''((filename.size() > 2 && filename[1] == ':') || filename.starts_with("\\\\\\\\")
? LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR : 0) | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS;'''
if old in s:
s = s.replace(old, new, 1)
p.write_text(s)
p = vulkan / "VulkanFunctions.cpp"
s = p.read_text()
if '#include "aurora_vulkan_hooks.h"' not in s:
marker = 'namespace dawn::native::vulkan {'
assert marker in s
s = s.replace(marker, '#include "aurora_vulkan_hooks.h"\n\n' + marker, 1)
for old, new in [
('GET_GLOBAL_PROC(CreateInstance);', 'CreateInstance = AuroraCreateInstance(GetInstanceProcAddr);'),
('GET_INSTANCE_PROC(CreateDevice);', 'CreateDevice = AuroraCreateDevice(GetInstanceProcAddr, instance);'),
('GET_INSTANCE_PROC(EnumeratePhysicalDevices);', 'EnumeratePhysicalDevices = AuroraEnumeratePhysicalDevices(GetInstanceProcAddr, instance);')]:
assert old in s, old
s = s.replace(old, old + '\n ' + new, 1)
p.write_text(s)
# Fragment density maps.
p = vulkan / "VulkanBackend.cpp"
s = read(p)
if '#include "aurora_fdm.inc"' not in s:
write(p, s + '#include "aurora_fdm.inc"\n')
insert(vulkan / "VulkanExtensions.h", " RasterizationOrderAttachmentAccess,\n",
" FragmentDensityMap,\n")
insert(vulkan / "VulkanExtensions.cpp",
' {DeviceExt::RasterizationOrderAttachmentAccess, "VK_EXT_rasterization_order_attachment_access"},\n',
' {DeviceExt::FragmentDensityMap, "VK_EXT_fragment_density_map"},\n')
insert(vulkan / "VulkanExtensions.cpp", " case DeviceExt::EnumCount:\n",
" // Aurora only attaches maps to dynamic rendering passes (aurora_fdm.inc).\n"
" case DeviceExt::FragmentDensityMap:\n"
" hasDependencies = HasDep(DeviceExt::DynamicRendering);\n"
" break;\n\n",
after=False)
insert(vulkan / "VulkanInfo.h", " VkPhysicalDeviceExtendedDynamicStateFeaturesEXT extendedDynamicStateFeatures;\n",
" VkPhysicalDeviceFragmentDensityMapFeaturesEXT fragmentDensityMapFeatures;\n")
insert(vulkan / "VulkanInfo.h", " VkPhysicalDeviceDrmPropertiesEXT drmProperties;\n",
" VkPhysicalDeviceFragmentDensityMapPropertiesEXT fragmentDensityMapProperties;\n")
insert(vulkan / "VulkanInfo.cpp",
" // Use vkGetPhysicalDevice{Features,Properties}2 if required to gather information about\n",
" if (info.extensions[DeviceExt::FragmentDensityMap]) {\n"
" featuresChain.Add(&info.fragmentDensityMapFeatures,\n"
" VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT);\n"
" propertiesChain.Add(&info.fragmentDensityMapProperties,\n"
" VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT);\n"
" }\n\n",
after=False)
insert(vulkan / "DeviceVk.cpp", '#include "src/dawn/native/vulkan/DeviceVk.h"\n',
'#include "aurora_fdm.h"\n')
insert(vulkan / "DeviceVk.cpp", " usedKnobs.extensions = mDeviceInfo.extensions;\n",
" // Aurora: fragment density maps for its immersive eye passes, only on request\n"
" // (aurora_fdm.inc).\n"
" if (!AuroraFdmWanted(mDeviceInfo, IsToggleEnabled(Toggle::VulkanUseDynamicRendering) &&\n"
" !HasFeature(Feature::DawnLoadResolveTexture))) {\n"
" usedKnobs.extensions.set(DeviceExt::FragmentDensityMap, false);\n"
" }\n")
insert(vulkan / "DeviceVk.cpp",
" usedKnobs.extendedDynamicStateFeatures = mDeviceInfo.extendedDynamicStateFeatures;\n"
" featuresChain.Add(&usedKnobs.extendedDynamicStateFeatures);\n"
" }\n",
"\n"
" if (usedKnobs.HasExt(DeviceExt::FragmentDensityMap)) {\n"
" usedKnobs.fragmentDensityMapFeatures = mDeviceInfo.fragmentDensityMapFeatures;\n"
" // Aurora's maps are immutable, read when a render pass is recorded.\n"
" usedKnobs.fragmentDensityMapFeatures.fragmentDensityMapDynamic = VK_FALSE;\n"
" featuresChain.Add(&usedKnobs.fragmentDensityMapFeatures);\n"
" }\n")
insert(vulkan / "DeviceVk.cpp", " mStaticSamplerCache.clear();\n",
"\n AuroraFdmDestroy(this);\n")
insert(vulkan / "RenderPipelineVk.cpp", " createInfo.renderPass = nullRenderPass;\n",
"\n"
" // Aurora: any pipeline may draw in an eye pass with a fragment density map\n"
" // (aurora_fdm.inc).\n"
" if (device->GetDeviceInfo().HasExt(DeviceExt::FragmentDensityMap)) {\n"
" createInfo.flags |= VK_PIPELINE_CREATE_RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT;\n"
" }\n")
insert(vulkan / "CommandBufferVk.cpp", '#include "src/dawn/native/vulkan/CommandBufferVk.h"\n',
'#include "aurora_fdm.h"\n')
insert(vulkan / "CommandBufferVk.cpp", " // TODO(crbug.com/463893794): Handle ExpandResolveTexture.\n",
" // Aurora: the fragment density map bound to the first color attachment's view\n"
" // (aurora_fdm.inc).\n"
" VkRenderingFragmentDensityMapAttachmentInfoEXT fragmentDensityMap;\n"
" if (attachmentMask[ColorAttachmentIndex(uint8_t(0))]) {\n"
" const ::VkImageView densityMap = AuroraFdmViewFor(\n"
" device, renderPass->colorAttachments[ColorAttachmentIndex(uint8_t(0))].view.Get());\n"
" if (densityMap != VK_NULL_HANDLE) {\n"
" fragmentDensityMap.sType =\n"
" VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_INFO_EXT;\n"
" fragmentDensityMap.pNext = renderInfo.pNext;\n"
" fragmentDensityMap.imageView = densityMap;\n"
" fragmentDensityMap.imageLayout = VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT;\n"
" renderInfo.pNext = &fragmentDensityMap;\n"
" }\n"
" }\n\n",
after=False)