Repository navigation
feat(video): render::readback reads a texture back to RGBA without an encoder - #8056
Conversation
Quest-Claim: f7983bdb14c1f740
… encoder Exporter's CPU route now reads through the same public Readback. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 21 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. |
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed head: d217f85.
No actionable findings in this change.
Direction: extracting the existing staging-buffer pool into render::readback fits the encoder-free RGBA consumer without introducing a second implementation. The exporter still performs its RGBA-to-I420 conversion after the shared readback; its stricter texture-usage requirements remain intact. I checked the pool's pending-handle ownership and reuse, mapping-error cleanup, padded-row removal, the renderer's texture contract, and the updated test selection.
Validation limits: this was a GitHub-only source review. I did not execute the GPU tests, Clippy, or the workspace checks, and the PR's reported local results were not independently reproduced. GitHub's Check was still in progress when inspected. This comment is not an approval or a merge-readiness determination.
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
render::readbackextracted — the private staging-bufferReadback/Stagedpair moved out ofrender/export.rsinto a publicrender::readback::{Readback, Pending};Readback::newnow rejects a zero size and returnsResult, andPending::waitreturnsconvert::Rgba(built by the newRgba::new) so the picture carries its size.- One readback path —
Exporter'sRoute::Readbackslot owns aReadback,Exporter::DEPTHisReadback::DEPTH, and the size/format/usage check is shared asreadback::check, which changesExporter::copy's refusal text to "cannot read". - Tests and runner —
render::readback::testscovers a byte-exact round trip at 60 px (padded staging rows), the depth drop, and refusal of a mismatched or non-COPY_SRCtexture; the exporter keeps an I420 route test; the nightlyrs render-swrecipe now selects the new tests. - Quest retired —
quest/m1/video-readback.mdand its m1 README line are deleted per the completion convention.
I checked the parts a move like this usually breaks: the staging pool accounting (free/allocated, including the failed-mapping decrement) and the map_async → poll(Wait{submission_index}) → get_mapped_range → unmap lifecycle are unchanged; Exporter::DEPTH stays 3 for the platform GPU routes that also size their pools from it; the nextest filter still selects the pre-existing render::export::tests::* and render::export::nv12::tests::* cases; and the new tests are reachable from a real --run-ignored caller, so no sh/gh/test-inventory.allow entry is needed. The additive module needs no MIGRATE.md note under the current rule, which supersedes the deleted quest's suggestion to add one.
deepseek-v4.1-flash-1017 (free via Pullfrog for OSS) | 𝕏
Bump the moq submodule to moq-dev/moq@d01819803, which includes moq-video's encoder-free texture readback (moq-dev/moq#8056). moq-tokio dropped its aws-lc-rs feature when native cryptography moved to rind (moq-dev/moq#7873), so the studio asks only for `net`. Finishes quest/m0/pin-readback.md, unblocking the Linux virtual camera. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Quest:
quest/m1/video-readback.md(finished and deleted here).Problem
A consumer that needs a rendered picture's raw RGBA, with no encoder behind it (such as a Linux virtual camera), could only reach moq-video's GPU readback through
render::export::Exporter, whose setup probes for an encoder. The alternative was copying the staging-buffer pool, row unpadding, and mapping lifecycle out of the crate.Approach
render/export.rsinto a publicrender::readbackmodule:Readback::new(device, queue, size),Readback::copy(&texture) -> Option<Pending>(non-blocking,NoneonceReadback::DEPTHcopies are in flight), andPending::wait() -> convert::Rgba(tightly packed rows).Exporter's CPU route now copies throughReadbackand converts itsRgbato I420, as before.Exporter::DEPTHis defined asReadback::DEPTH.Rgba8Unorm), and usage check is shared.Readbackasks only forCOPY_SRC;Exporterstill also asks forTEXTURE_BINDING, which its GPU routes sample through.render::readback::testschecks the round trip byte for byte at a width whose rows need padding (60 px), dropping past the depth, and refusing a mismatched or non-COPY_SRCtexture. The exporter keeps a test that its readback route hands back I420.just rs render-swnow runsrender::readback::testsas well.Impact
moq_video::render::readback::{Readback, Pending}(behind therenderfeature). Additive only.Exporter::copy's mismatch error text now says "cannot read" instead of "cannot export".Choices made without asking
render::readback::{Readback, Pending}, mirroringrender::export::{Exporter, Pending}, as the quest recommended.Pending::waitreturns the existingconvert::Rgba(size plus packed bytes) rather than a bareVec<u8>, so the picture carries its size;into_data()gives theVec.Rgba8Unormis accepted, matchingExporter.Alternatives
Readbackinsiderender::exportand make it public there: rejected, since it has nothing to do with exporting to an encoder.Follow-ups
Validation
just rs render-sw(Mesa lavapipe): all 13 GPU tests pass, including the newrender::readback::tests::*.cargo clippy -p moq-video --features render --all-targets -D warnings: clean.just check: passes (11918 tests).Review
Head 10384d6: review exempt, a conflict-free merge of origin/main (GitHub had reported the branch as conflicting).
Codex gpt-6.1-sol, medium effort, round 1 on
d217f853af46587487627ef9936d2adcc157b013: no findings.(Written by Claude Opus 5.5)
🤖 Generated with Claude Code