Repository navigation
Conversation
"Create shader table" used to cover everything up to DispatchRays. It now covers only the table build, under a new "Raytraced froxel shadows" parent that spans the same work as before, with sibling zones for options and parameters, material data, UseResources and DispatchRays. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The raytraced froxel fog built a new Tr2RtShaderTableAL every frame, so each frame paid for a CreateCommittedResource on a fresh upload buffer and then released it. Keep the table as a member and rebuild it in place with Update, as Tr2RaytracingManager and Tr2LightManager already do since carbonengine#123, falling back to Create when Update fails. The records still have to be written every frame: the hit groups carry per-object constant addresses from the per-frame upload ring, and PrepareRaytracedShadows clears and refills the description each frame. Also hoist the option, value and parameter names into statics so the block no longer interns ten BlueSharedStrings per frame. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The raytraced froxel fog shadow path in
Tr2VolumetricsRenderer::RenderFogbuilt a brand newTr2RtShaderTableALevery frame. On DX12 that means aCreateCommittedResourcefor a fresh upload buffer, which is filled and then released at the end of the scope. It was the largest native per-frame cost found while profiling frame-rate drops in the EVE Frontier client: about 0.56 ms of main-thread time every frame, with spikes up to 1.7 ms, whenever raytraced shadows are on.#123 already added
Tr2RtShaderTableAL::Update, which rebuilds a table in place using persistent per-back-buffer upload buffers, and movedTr2RaytracingManagerandTr2LightManagerover to it. The volumetrics renderer was the one caller still left onCreate-per-frame. This PR moves it over the same way.Changes
1. Finer Tracy zones (
Split the raytraced froxel fog zone into finer Tracy zones)The old
"Create shader table"zone was opened partway through the block and ran to the end of it. So it timedSetOption/SetParameter,ApplyMaterialDataForRtState,UseResourcesandDispatchRaysas well, not just the table. Now:Raytraced froxel shadowsCreate shader tablezone covered, so old and new captures compare directlyCreate shader tableSet options and parametersSetOption×2,SetParameter×3Apply material dataSetRtPipelineState,ApplyMaterialDataForRtState,UseAccelerationStructurerenderContext.UseResourcesDispatchRaysrenderContext.DispatchRays2. The fix (
Reuse the froxel fog shadow shader table across frames)Tr2VolumetricsRenderernow owns aTr2RtShaderTableAL m_fogShadowShaderTable, declared afterm_fogConstantBufferso it is destroyed first. Each frame it callsUpdate, falls back toCreatewhen the table isn't valid yet orUpdatefails, and logs and bails if the table is still invalid. This is the same patternTr2RaytracingManager::RenderShadowsandTr2LightManager::RenderRaytracedShadowsuse.static const BlueSharedStrings, so the block no longer interns ten strings per frame.No behaviour change is intended: the table holds the same records, filled the same way, and only lives in a different buffer.
Why the table is still written every frame
The original idea was to build the table once and rebuild it only when the pipeline state or library changed. That doesn't hold here:
EveSpaceScene::PrepareRaytracedShadows→Tr2RaytracingGeometry::PrepareShaderTableDescriptioncallsClear()on every raycaster's description each frame, including the volumetrics one, then refills the hit groups. The fog then appends one ray-gen and one miss record.perObjectData,vertexBufferData). These come from the descriptor cache's per-frame upload ring, so they change from frame to frame and the records have to be rewritten each frame.DescriptorStateCache::UploadConstantsalready uploads each constant buffer at most once per frame, shared across all tables. Re-filling the records is cheap, so the cost was entirely the per-frame resource allocation and release.Tr2Effect::SetOptionalready returns early when the value hasn't changed, so the options needed no extra guard.Measurements
EVE Frontier client, local dev stack,
/buildflavor=trinitydev, DX12, shadow quality = raytraced. Same character and position in the same solar system for both runs; 12 s Tracy capture each (tracy-capture.exe, C++ zones only, all telemetry categories active), exported withtracy-csvexport.exe._trinity_dx12_trinitydev.pyd(v8.1.0, 21edab0).The fog shadow block
Create shader tablebefore,Raytraced froxel shadowsafter)Create shader table(table only)Set options and parametersApply material datarenderContext.UseResourcesDispatchRaysTr2RaytracingManagerCreate shader tableThe block is about 17× cheaper on average, and its worst frame drops from 1.7 ms to 0.18 ms. The
Create shader tablepart on its own now costs about what theTr2RaytracingManagerone does. The remaining spikes are inDispatchRays(command list recording), not the table.Whole frame (same captures)
BlueOS/PumpOSmeanTrinity/device/OnTickmeanTrinity/device/RenderJobsmeanAbsolute frame rates in these captures are low because they use the TrinityDev flavour with Tracy capturing every telemetry category. Both runs are equally affected, so the comparison holds, but they shouldn't be compared with fps from an internal or release client.
Testing
trinity_dx12, TrinityDev config, VS 2026 / v145.CCP_LOGERRpath.Updateforwards toCreate, per Cache RT shader table state and skip unused RT work #123, so behaviour matches the other two callers.-DBUILD_TESTING=OFF; see below). The existing Cache RT shader table state and skip unused RT work #123 test coversUpdateacross frames with changing constants and record counts.Notes for reviewers
These only affected the local build. None of them are part of this change:
.claude/worktrees/...),carbon-blueexposure's compiler check fails withrc.exe ... manifest.rc(3) : error RC2136 : missing '=' in EXSTYLE=<flags>. The embedded manifest path gets too long for rc's string literal; building through a short junction works.crashpad(pulled in by thecarbon-exefilehost dependency) runsvswhere -products * -latest. With SQL Server Management Studio 22 installed, that returns SSMS instead of Visual Studio, and mini_chromium'swin_helper.pyfails running itsvcvarsall.bat. For the measurement build I droppedcarbon-exefilelocally and configured with-DBUILD_TESTING=OFF.🤖 Generated with Claude Code