Skip to content

Commit 87fb8ac

Browse files
committed
🔧
1 parent cf63d0a commit 87fb8ac

1 file changed

Lines changed: 38 additions & 5 deletions

File tree

apps/example/src/SharedTextureMemory/SharedTextureMemory.tsx

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,18 @@ struct VsOut {
1515
@location(0) uv: vec2f,
1616
};
1717
18+
struct Uniforms {
19+
// Per-axis scale applied to UVs *around the center* so that the canvas
20+
// samples a sub-rectangle of the texture matching the canvas aspect ratio.
21+
// 'cover' fit: one axis is 1.0, the other is canvasAR / textureAR (or its
22+
// reciprocal), whichever is < 1 — i.e. we crop on the longer axis.
23+
uvScale: vec2f,
24+
};
25+
26+
@group(0) @binding(0) var srcTex: texture_2d<f32>;
27+
@group(0) @binding(1) var srcSampler: sampler;
28+
@group(0) @binding(2) var<uniform> u: Uniforms;
29+
1830
@vertex
1931
fn vs_main(@builtin(vertex_index) vid: u32) -> VsOut {
2032
// Full-screen triangle.
@@ -34,12 +46,10 @@ fn vs_main(@builtin(vertex_index) vid: u32) -> VsOut {
3446
return out;
3547
}
3648
37-
@group(0) @binding(0) var srcTex: texture_2d<f32>;
38-
@group(0) @binding(1) var srcSampler: sampler;
39-
4049
@fragment
4150
fn fs_main(in: VsOut) -> @location(0) vec4f {
42-
return textureSample(srcTex, srcSampler, in.uv);
51+
let uv = vec2f(0.5) + (in.uv - vec2f(0.5)) * u.uvScale;
52+
return textureSample(srcTex, srcSampler, uv);
4353
}
4454
`;
4555

@@ -144,9 +154,24 @@ export const SharedTextureMemory = () => {
144154
memory: GPUSharedTextureMemory;
145155
texture: GPUTexture;
146156
bindGroup: GPUBindGroup;
157+
uniformBuffer: GPUBuffer;
147158
};
148159
let current: Bound | null = null;
149160

161+
// 'cover' fit: scale UVs around their center so the longer axis of the
162+
// texture is cropped to match the canvas aspect ratio.
163+
const computeUvScale = (texW: number, texH: number): [number, number] => {
164+
const canvasAR = canvas.width / canvas.height;
165+
const texAR = texW / texH;
166+
if (texAR > canvasAR) {
167+
// Texture is wider than the canvas: crop horizontally.
168+
return [canvasAR / texAR, 1];
169+
} else {
170+
// Texture is taller than (or equal to) the canvas: crop vertically.
171+
return [1, texAR / canvasAR];
172+
}
173+
};
174+
150175
const bindFrame = (frame: VideoFrame): Bound | null => {
151176
try {
152177
const memory = device.importSharedTextureMemory({
@@ -159,14 +184,21 @@ export const SharedTextureMemory = () => {
159184
frame.release();
160185
return null;
161186
}
187+
const uniformBuffer = device.createBuffer({
188+
size: 16, // vec2<f32> padded to 16-byte uniform alignment
189+
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
190+
});
191+
const [sx, sy] = computeUvScale(frame.width, frame.height);
192+
device.queue.writeBuffer(uniformBuffer, 0, new Float32Array([sx, sy]));
162193
const bindGroup = device.createBindGroup({
163194
layout: pipeline.getBindGroupLayout(0),
164195
entries: [
165196
{ binding: 0, resource: texture.createView() },
166197
{ binding: 1, resource: sampler },
198+
{ binding: 2, resource: { buffer: uniformBuffer } },
167199
],
168200
});
169-
return { frame, memory, texture, bindGroup };
201+
return { frame, memory, texture, bindGroup, uniformBuffer };
170202
} catch (e) {
171203
console.warn("[SharedTextureMemory] bindFrame failed:", e);
172204
frame.release();
@@ -177,6 +209,7 @@ export const SharedTextureMemory = () => {
177209
const releaseBound = (b: Bound) => {
178210
b.memory.endAccess(b.texture);
179211
b.texture.destroy();
212+
b.uniformBuffer.destroy();
180213
b.frame.release();
181214
};
182215

0 commit comments

Comments
 (0)