Workbench: Hardware raytraced shadows

Implement optional hardware raytraced shadows for the Workbench engine.

They can be enabled in the `Preferences > Viewport > Quality` settings.
The option will be shown as inactive if the current backend/GPU doesn't
support hardware ray queries (only Vulkan is supported ATM).
A new `gpu.capabilities.ray_query_support_get()` has been added to the
Python API to support this UI functionality.

The visual results are the same as the stencil shadows implementation,
but it provides a significant performance boost on modern hardware.

The raytracing functionality has been implemented in a fragment shader
that mimics the output of stencil-based implementation, so the render
pipeline stays mostly the same.

Co-authored by: Jeroen Bakker

Pull Request: https://projects.blender.org/blender/blender/pulls/161047
This commit is contained in:
Miguel Pozo 2026-07-21 16:57:31 +02:00 • committed by Miguel Pozo
parent 5cfcffda7b
commit a6b708c1f2
32 changed files with 310 additions and 83 deletions

View file

@ -9,6 +9,7 @@ Use this script as `blender --background --python gpu_info.py`.
"""
import bpy
import sys
import json
# Render with workbench to initialize the GPU backend otherwise it would fail when running in
# background mode as the GPU backend won't be initialized.
@ -21,9 +22,14 @@ bpy.ops.render.render(animation=False, write_still=False)
# Import GPU module only after GPU backend has been initialized.
import gpu
print('GPU_VENDOR:' + gpu.platform.vendor_get())
print('GPU_RENDERER:' + gpu.platform.renderer_get())
print('GPU_VERSION:' + gpu.platform.version_get())
print('GPU_DEVICE_TYPE:' + gpu.platform.device_type_get())
print('<GPU_INFO>')
print(json.dumps({
"VENDOR": gpu.platform.vendor_get(),
"RENDERER": gpu.platform.renderer_get(),
"VERSION": gpu.platform.version_get(),
"DEVICE_TYPE": gpu.platform.device_type_get(),
"RAY_QUERY_SUPPORT": gpu.capabilities.ray_query_support_get(),
}))
print('</GPU_INFO>')
sys.exit(0)

View file

@ -18,6 +18,7 @@ import time
import multiprocessing
import traceback
import re
import json
from pathlib import Path
@ -229,7 +230,7 @@ def diff_output(test, oiiotool, fail_threshold, fail_percent, verbose, update):
return test
def get_gpu_device_vendor(blender, gpu_backend):
def get_gpu_device_info(blender, gpu_backend):
command = [
blender,
"--background",
@ -239,15 +240,28 @@ def get_gpu_device_vendor(blender, gpu_backend):
"--python",
str(pathlib.Path(__file__).parent / "gpu_info.py")
]
try:
completed_process = subprocess.run(command, stdout=subprocess.PIPE, universal_newlines=True)
for line in completed_process.stdout.splitlines():
if line.startswith("GPU_DEVICE_TYPE:"):
vendor = line.split(':')[1].upper()
return vendor
except Exception:
return None
return None
completed_process = subprocess.run(command, stdout=subprocess.PIPE, universal_newlines=True)
info = completed_process.stdout.split("<GPU_INFO>")[1].split("</GPU_INFO>")[0]
return json.loads(info)
def get_gpu_device_vendor(blender, gpu_backend):
return get_gpu_device_info(blender, gpu_backend)["DEVICE_TYPE"]
def get_gpu_device_ray_queries_support(blender, gpu_backend):
command = [
blender,
"--background",
"--factory-startup",
"--gpu-backend",
gpu_backend,
"--python-expr",
'import gpu; gpu.init(); print("GPU_RAY_QUERIES_SUPPORT:", gpu.capabilities.ray_query_support_get())'
]
completed_process = subprocess.run(command, stdout=subprocess.PIPE, universal_newlines=True)
return "GPU_RAY_QUERIES_SUPPORT: True" in completed_process.stdout
class Report:

View file

@ -37,10 +37,17 @@ BLOCKLIST_AMD_VK = [
".*"
]
BLOCKLIST_NON_RT = [
"shadows_rt.blend",
]
def setup():
import bpy
# The setting will be ignored if the system/backend doesn't support ray queries.
bpy.context.preferences.system.use_rt_shadows = not bpy.context.scene.get("Workbench_disable_rt", False)
for scene in bpy.data.scenes:
if scene.get("Workbench_skip_setup", False):
continue
@ -113,11 +120,16 @@ def main():
if args.gpu_backend == "vulkan":
blocklist += BLOCKLIST_VULKAN
gpu_vendor = render_report.get_gpu_device_vendor(args.blender, args.gpu_backend)
gpu_info = render_report.get_gpu_device_info(args.blender, args.gpu_backend)
gpu_vendor = gpu_info["DEVICE_TYPE"]
if os.getenv("BLENDER_TEST_IGNORE_VENDOR_BLOCKLIST") is None:
if gpu_vendor == "AMD" and args.gpu_backend == "vulkan":
blocklist += BLOCKLIST_AMD_VK
if not gpu_info["RAY_QUERY_SUPPORT"]:
blocklist += BLOCKLIST_NON_RT
report = WorkbenchReport("Workbench", args.outdir, args.oiiotool, variation=args.gpu_backend, blocklist=blocklist)
if args.gpu_backend == "vulkan":
report.set_compare_engine('workbench', 'opengl')