Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion packages/producer/src/services/distributed/renderChunk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,6 @@ export async function renderChunk(

const videoCaptureBeyondViewport = resolveVideoCaptureBeyondViewport(
planVideos?.videos.length ?? 0,
"software",
);

// ── Per-chunk work + frames directories ──
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@ import { resolveVideoCaptureBeyondViewport } from "./captureBeyondViewport.js";

describe("resolveVideoCaptureBeyondViewport", () => {
it("leaves no-video renders on the engine default", () => {
expect(resolveVideoCaptureBeyondViewport(0, "software")).toBeUndefined();
expect(resolveVideoCaptureBeyondViewport(0, "hardware")).toBeUndefined();
expect(resolveVideoCaptureBeyondViewport(0)).toBeUndefined();
});

it("keeps video renders on the fast viewport-bound path under software rendering", () => {
expect(resolveVideoCaptureBeyondViewport(1, "software")).toBe(false);
});

it("preserves the beyond-viewport video workaround under hardware rendering", () => {
expect(resolveVideoCaptureBeyondViewport(1, "hardware")).toBe(true);
it("forces beyond-viewport for any video render so the bottom edge is not clipped", () => {
// Regression: software hosts (including every distributed chunk render,
// which resolves as "software") previously returned false here and clipped
// ~87 bottom rows to black on video comps.
expect(resolveVideoCaptureBeyondViewport(1)).toBe(true);
expect(resolveVideoCaptureBeyondViewport(5)).toBe(true);
});
});
29 changes: 19 additions & 10 deletions packages/producer/src/services/render/captureBeyondViewport.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
export type ResolvedBrowserGpuMode = "software" | "hardware";

/**
* Native video surfaces can need Chrome's beyond-viewport compositor on
* hardware-accelerated captures, but that path is a full-surface software
* re-rasterization tax on SwiftShader/CPU render hosts.
* Native video surfaces need Chrome's beyond-viewport screenshot path or the
* viewport-bound capture clips the bottom edge of the frame — the same
* #1094 tall-portrait guard the alpha capture paths already hardcode
* (`captureScreenshotWithAlpha` / `captureAlphaPng`).
*
* This used to be gated to hardware-GPU captures to skip the full-surface
* software re-rasterization tax on SwiftShader/CPU render hosts. But that left
* software hosts clipping ~87 bottom rows to black on video comps — and every
* distributed chunk render resolves as "software", so the entire distributed
* fleet shipped video renders with a black bottom band. Correct output wins
* over the software perf optimization: enable beyond-viewport for any render
* that has a native video surface, regardless of GPU mode.
*
* ponytail: blanket-on for video. If the software re-raster tax proves
* significant on the distributed fleet, narrow it back to comps whose content
* actually reaches the bottom edge — but that needs a reliable clip predictor
* first, and a black band is unshippable in the meantime.
*/
export function resolveVideoCaptureBeyondViewport(
videoCount: number,
browserGpuMode: ResolvedBrowserGpuMode,
): boolean | undefined {
export function resolveVideoCaptureBeyondViewport(videoCount: number): boolean | undefined {
if (videoCount <= 0) return undefined;
return browserGpuMode === "hardware";
return true;
}
5 changes: 1 addition & 4 deletions packages/producer/src/services/renderOrchestrator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1899,10 +1899,7 @@ export async function executeRenderJob(
browserTimeout: cfg.browserTimeout,
});
updateCaptureObservability({ browserGpuMode: resolvedBrowserGpuMode });
const videoCaptureBeyondViewport = resolveVideoCaptureBeyondViewport(
composition.videos.length,
resolvedBrowserGpuMode,
);
const videoCaptureBeyondViewport = resolveVideoCaptureBeyondViewport(composition.videos.length);

const captureOptions: CaptureOptions = {
width,
Expand Down
Loading