Epic: built-in effects stack (ReShade FX compatible) + cel-shading avatars #542
Labels
No labels
amd
avatars
bug
builder
cannot-reproduce
crash
epic
feature
from-viewer
gl-removal
known-limitation
monitoring
parity
perf
platform
priority
critical
priority
high
priority
low
priority
medium
provenance
rendering
rt
status
in-progress
status
testing
status
up-next
triage
ui
upstream
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
sky_line/Slipstream#542
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Design note and plan for #186: a built-in, ReShade FX compatible effects stack that runs inside our VK post chain, with a native cel-shading effect, optionally limited to avatars / rigged mesh, as the first built-in.
Recommendation: GO. The cel-shading track can start now; it doesn't depend on the ReShade runtime. The ReShade FX track is GO contingent on Phase 0, a vendor-and-compile smoke test that is cheap and decisive.
1. Goals
.fx/.fxh, the textures they reference (source = "..."), and ReShade preset.inifiles. They come from a folder the user picks, which can be an existing ReShadereshade-shadersinstall. Our own format is used only for built-ins, and only where FX can't express something (in-pass hooks).Non-goals for v1: ReShade's add-on API (the DLL plugin ABI), D3D-only intrinsics, depth from HUD space, and effects on 360 captures (see 5.6).
2. What exists today (code survey,
vulkan-port-tb@9e512297ca)Post chain order (
indra/newview/vkgfx/llcleanrenderervk.cpp,recordWorldat :23547):recordDeferredLighting)sceneHdr(), render-res, jitteredrecordTAA:15169,recordFSR:15798,recordSnapAccum:15634,recordSceneUpscaleBlit:16438)mHdrdisplay-res, unjittered, RGBA16F linear (llcleanrenderervk.h:1043-1045)recordTonemaprecordAAFXAA/SMAAmAAColorRGBA16F -> chain out@setspheremSphereTmp/mFinalColorrecordFinal(Photo Studio "Lightbox" lens/vignette/CVD/grain/dither/CAS,clean_final.frag)mFinalColor-> swapchainrecordCaptureAt(1): user snapshot, world onlyrecordDepthUpscale(#181), only whenmScaleddisplayDepth()(.h:1100)mWorldOverlayHook(3D overlays, name tags #468)recordWorldprepareFinal(..., force)(:18145, header.h:490-494) is how RLVa's sphere already forces the chain to end inmFinalColor. FX can reuse the same mechanism.mRenderW x mRenderH, everything from the TAA resolve on runs at display size (.h:1053-1062). Target generation registry (.h:1063-1090): any new size-dependent target / descriptor set must follow its rules. External modules get the generation through their Frame, never a view-handle compare.D32_SFLOAT, no stencil (.h:1026); reversed-Z, near = 1 / far = 0 (llcleanrenderervk.cpp:127-132).clean_depth_up.compproduces the unjittered display depth, but only on scaled frames. At scale 1 under TAA,displayDepth()is the jitteredmDepth.mAoNormalRG16F (.h:1414,clean_prepass_normal.frag), on AO frames only. The deferred G-buffer has G1 oct N/Ng and G2.w "model byte" with bits 3-7 free (vkclean/shaders/clean_gbuffer.glsl:8-13, :48). Deferred is not used for captures / offscreen renders (.h:1925-1926).mMotionRG16F, UV units, current minus previous, unjittered (.h:1673-1682,clean_prepass_normal.fragheader). Written by the pre-pass when temporal is on.flagsbit0 = rigged, bit9 = worn rigid attachment (skin_id= joint-table slot), bit1 alpha, bit2 mask, bit15 vegetation (indra/newview/llcleaninstancestore.h:61-67;clean_draw.vert:118).SkinMeta.avatar_idx(llcleanskinstore.h:78-80) and the per-avatar joint slot (ensureAvatarSlot,.h:104-115) give a per-pixel avatar index without any CPU per-face work. Rigged draws already have their own pre-pass pipeline twins (mPreMvRigPipeetc.,llcleanrenderervk.h:1683-1688) and skinned verts inmSkinVbo(used byrecordSelection:8082 to redraw rigged geometry).lightSurface()(clean_surface_light.glsl:86) shared by forward andclean_deferred_light.comp.recordWorld(beginOffscreen:15439,mOffscreen). Supersampled snapshots (#417) accumulate N jittered recordings.vk_device_lost_handler(llappviewer.cpp:4043) writes diagnostics andgpuLostWriteMarker()(:3823), which tells the next launch.vkBreadcrumb(cmd, name)(vk_common.h:38) uses static names (llcleanfsr3vk.cpp:545).gVkFatalHandlerturns a failingVK_CHECKinto LL_ERRS, so user content must never go throughVK_CHECK.gpuSubMark/gpuTimerMark(.h:1175).vkclean/regen_world_spv.py->glslc-> embeddedvk_world_shaders_spv.h. No runtime GLSL compiler (no glslang/shaderc in 3p). Vulkan headers come from the system SDK (indra/cmake/VulkanGfx.cmake), so SPIRV-Headers are not guaranteed on CI / Windows cross.vk_swapchain.cpp:63), BGRA (swapBytesToRGB,llcleanrenderervk.cpp:16119).skins/default/xui/en/panel_photo_studio_*.xml), slot model with section dropdowns + history (slfloaterphotostudio.h:67-68, 98-170).3. Architecture
3.1 Compiler: vendor
reshadefx(BSD-3) and run no GLSL compiler at runtimecrosire/reshadesource/effect_*(lexer, preprocessor, parser, symbol table, expression,effect_codegen_spirv.cpp, headers). That's about 20 files. Also vendor the Khronosspirv.hpp+GLSL.std.450.h(MIT-style; system SDK headers aren't guaranteed). Location:indra/newview/vkgfx/third_party/reshadefx/withLICENSE.md+NOTICE.effect_codegen_spirv.cpp~:984-1094): set 0 = global uniform UBO, set 1 = combined samplers, set 2 = storage images. Options:vulkan_semantics,flip_vert_y,uniforms_to_spec_constants,enable_16bit_types.(file hash, includes hash, defines, BUFFER size)-> SPIR-V cache on disk. Pipelines go throughvk_pipecache.__RESHADE__value). Update deliberately.3.2 Runtime (
newview/vkgfx/llcleanfxvk.{h,cpp}, a module like FSR3 / god rays)Width/Height/MipLevels/Format,pooled), created withVK_IMAGE_CREATE_MUTABLE_FORMAT_BIT+ UNORM/SRGB view pairs forSRGBTexture/SRGBWriteEnable. Samplers from sampler states. Storage images for compute passes. An own S8/D24S8 stencil attachment for passes withStencilEnable(our depth has no stencil). Imagesourcefiles loaded via LL decoders (png/jpg/bmp/tga) + a small DDS and.cubeLUT reader.VertexCount/PrimitiveTopology, blend / write-mask / stencil states, up to 8 RTs,ClearRenderTargets,GenerateMipMaps). Compute passes useDispatchSizeX/Y/Z. Techniques run in user order. Barriers are derived from each pass's read/write sets.sourcespecials:timer,frametime,framecount,date,pingpong,random,key/mousebutton/mousepoint/mousedelta/mousewheel(from LL keyboard / window, only while the world has focus),bufready_depth(true),overlay_open(Photo Studio effects panel open),overlay_active/hovered(UI),screenshot(=mOffscreen).__RESHADE__,__RENDERER__= 0x20000+ (Vulkan),__VENDOR__/__DEVICE__,BUFFER_WIDTH/HEIGHT/RCP_*,BUFFER_COLOR_BIT_DEPTH(8 at the display point),BUFFER_COLOR_SPACE(1 sRGB; 2 scRGB at the HDR point),__SLIPSTREAM__(version) for opt-in extensions.ReShade.fxh(CC0-1.0,SPDXin its header) and a clean-roomReShadeUI.fxh. The upstream one has no licence (thereshade-shadersrepo has no LICENSE file), but it's only annotation macros..h:1084).gpuSubMarkwith interned names) and breadcrumb per pass.3.3 Injection points
recordAA(:26734), before RLVa sphere andrecordFinalmColorFormat-compatible, forced viaprepareFinal(force)BUFFER_COLOR_SPACE 1, 8-bitrecordTonemap(~:26661 -> :26718)mHdrRGBA16F linear, exposure-scaledBUFFER_COLOR_SPACE 2, 16-bitsceneHdr()render-res, jitteredWhy this order:
@setsphere).3.4 Input mapping
ReShade::BackBuffer/COLOR-> the chain's current image at the point.ReShade::DepthBuffer/DEPTH-> unjittered display depth. Runclean_depth_up.comp's unjitter mapping at 1:1 too when FX wants depth, otherwise depth effects shimmer under TAA. Our reversed-Z matches ReShade.fxh's defaultRESHADE_DEPTH_INPUT_IS_REVERSED 1. DefineRESHADE_DEPTH_LINEARIZATION_FAR_PLANEfrom the far clip (compile-time, recompile on draw-distance change). Alternative: hand effects linear depth / far and setFAR_PLANE 1. Pick in P1 after testing MXAO / DOF-style effects.update_texture_bindings):SLIPSTREAM_NORMAL(view-space normal, display res),SLIPSTREAM_MOTION(UV-unit MV),SLIPSTREAM_AVATAR_MASK(R8 / R16 id),SLIPSTREAM_SCENE_HDR. Effects that don't declare them are unaffected. Normals or motion force the corresponding pre-pass twin, as AO does.3.5 UI (recommendation)
panel_photo_studio_effects.xml+ section in the slot model). It sits next to grading, gets history / undo and Find for free, and holds:ui_categorycollapsibles,ui_text, tooltips.ini:Techniques=Name@file.fx,...,TechniqueSorting=,PreprocessorDefinitions=, one[file.fx]section ofuniform=values. Import and export as-is; store in~/.slipstreamviewer/fx/presets/. Unknown keys are preserved on round-trip.fx/dir + user-added folders. The "Import ReShade install" button points atreshade-shaders/Shaders+Textures.3.6 Safety
VK_CHECKon any user-content path. Pipeline / shader-module failure disables that effect with a message.robustBufferAccess2/robustImageAccess2on FX pipelines where availablellvrambudgetvk(soft cap, refuse load beyond it)gpuLostWriteMarkeralso records the last FX breadcrumb.--no-fx/ a settings key.dxgi.dll/opengl32.dllnext to the exe,VK_LAYER_reshade*/ENABLE_VKBASALT) -> one-time warning about double application.3.7 Performance budget
3.8 Snapshots
recordWorld). Thescreenshotsource = true;enabled_in_screenshot = falsetechniques are skipped.BUFFER_WIDTH/HEIGHTare compile-time, so a custom-size snapshot needs recompiling and re-creating effect targets at that size. Mitigations:3.9 Linux / Windows
windows-crosspreset) must compile the vendored reshadefx under clang-cl. It's plain C++17; watch for the/YuPCH note (keep it out of PCH).4. Cel-shading design (first built-in)
Pure post-processing can't do convincing toon shading. After lighting, albedo and light are baked together, so posterizing gives muddy bands. The design is therefore a hybrid:
4.1 Toon lighting (in-pass, material stage).
lightSurface(), a flagged surface usesclean_gbuffer.glsl:48). It is written from that same lookup in the G-buffer FS.lightSurface(), so forward-only paths (snapshots, mirror, probe captures) get the same look. Whole-scene mode just sets the global flag.4.2 Avatar mask (also used by FX scope and
SLIPSTREAM_AVATAR_MASK).avatar slot + 1, 0 = not avatar.RenderVKDepthPrepass, :25051) and runs offscreen too. When needed, it is forced on.mAoNormal, because both channels are used and it exists only on AO frames.clean_depth_up.comp(floor(pr + jitter)), for post-chain consumers.4.3 Outlines.
sceneHdr()after pass-1 lighting, before pass 2. TAA anti-aliases the lines, and alpha / water composite correctly on top.mExposureImg). Distance fade.mSkinVbo(world-space skinned normals already there), with front-face cull and clip-space extrusion along the normal (spec constant inclean_draw_rigged.vert).4.4 Controls:
RenderVKCel*, and get saved in Photo Studio presets.4.5 Not FX: cel lighting needs the in-pass hook, so it's a native render feature. The mask is still exposed to FX, so community outline / toon effects can be restricted to avatars too.
5. Compatibility strategy and known gaps
ReShade.fxh.ADDON_*macros undefined) or add-on-provided resourcespooledtexture sets (VRAM)__RENDERER__being D3Dreshade-shaderssample effects. The last four are user-installed only.6. Licensing
LICENSE.md), compatible with the LGPL-2.1 viewer. Keep the copyright notice in source + About / credits.ReShade.fxh: CC0-1.0 (SPDX line in the file). OK to ship.ReShadeUI.fxh: no licence found, so write a clean-room equivalent.7. Phased plan (sizes = agent-days, rough)
Ordering:
8. Risks
BUFFER_WIDTH/HEIGHT-> recompiles + target re-creation on resize and every custom-size snapshot (VRAM spike, hitch). Mitigated by the per-size cache + worker compile.DemoteToHelperInvocation, cf.vk_device.cpp:1338), validation errors, upstream drift. P0 measures this.9. Go / no-go
Cel shading (P6, P7): GO now. Native, fits the GPU-driven architecture (flag lookup via SSBO, MDI only, no per-face paths), low risk, and high user value.
ReShade FX runtime (P0-P5, P8): GO contingent on P0. Gate criteria:
spirv-valfor Vulkan 1.3If P0 fails badly, fall back to "Slipstream GLSL effect format for built-ins only" and drop compatibility.
Status: P0-P7 shipped (Beta 4/5) and closed (#543-#550). Only the compatibility sweep, #551 (P8), remains.
P0-P7 (effects runtime, ReShade FX, cel shading) shipped and closed (#543-#550). Only the compatibility sweep #551 (P8, low priority) remains and nothing is being worked on, so this moves from In Progress to To Do.
P0-P7 (effects runtime, ReShade FX, cel shading) have shipped and closed. Only the low-priority compatibility sweep #551 remains, so the epic goes back to the backlog.
Fixed in Slipstream 1.3.0 (stable): https://git.slipstreamviewer.org/sky_line/Slipstream/releases/tag/v1.3.0
If you still see this on 1.3.0, reply here and we'll reopen it.