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
2 changes: 1 addition & 1 deletion packages/webgpu/cpp/rnwgpu/api/GPUQueue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ void GPUQueue::copyExternalImageToTexture(
throw std::runtime_error("Invalid input for GPUQueue::writeTexture()");
}

if (source->flipY) {
if (source->flipY.value_or(false)) {
// Calculate the row size and total size
uint32_t rowSize = bytesPerPixel * source->source->getWidth();
uint32_t totalSize = source->source->getSize();
Expand Down
2 changes: 1 addition & 1 deletion packages/webgpu/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-native-wgpu",
"version": "0.5.8",
"version": "0.5.9",
"description": "React Native WebGPU",
"main": "lib/commonjs/index",
"module": "lib/module/index",
Expand Down
124 changes: 124 additions & 0 deletions packages/webgpu/src/__tests__/ExternalTexture.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -281,4 +281,128 @@ describe("External Textures", () => {
const image = encodeImage(result);
checkImage(image, "snapshots/f2.png");
});
it("flipY: false should not flip (same as omitting flipY)", async () => {
const result = await client.eval(
({ gpu, device, ctx, canvas, urls: { fTexture } }) => {
const module = device.createShaderModule({
label: "our hardcoded textured quad shaders",
code: /* wgsl */ `
struct OurVertexShaderOutput {
@builtin(position) position: vec4f,
@location(0) texcoord: vec2f,
};

@vertex fn vs(
@builtin(vertex_index) vertexIndex : u32
) -> OurVertexShaderOutput {
let pos = array(
// 1st triangle
vec2f( 0.0, 0.0), // center
vec2f( 1.0, 0.0), // right, center
vec2f( 0.0, 1.0), // center, top

// 2st triangle
vec2f( 0.0, 1.0), // center, top
vec2f( 1.0, 0.0), // right, center
vec2f( 1.0, 1.0), // right, top
);

var vsOutput: OurVertexShaderOutput;
let xy = pos[vertexIndex];
vsOutput.position = vec4f(xy, 0.0, 1.0);
vsOutput.texcoord = xy;
return vsOutput;
}

@group(0) @binding(0) var ourSampler: sampler;
@group(0) @binding(1) var ourTexture: texture_2d<f32>;

@fragment fn fs(fsInput: OurVertexShaderOutput) -> @location(0) vec4f {
return textureSample(ourTexture, ourSampler, fsInput.texcoord);
}
`,
});

const presentationFormat = gpu.getPreferredCanvasFormat();
const pipeline = device.createRenderPipeline({
label: "hardcoded textured quad pipeline",
layout: "auto",
vertex: {
module,
},
fragment: {
module,
targets: [{ format: presentationFormat }],
},
});

return fetch(fTexture).then((res) => {
return res.blob().then((blob) => {
return createImageBitmap(blob, {
colorSpaceConversion: "none",
}).then((source) => {
const texture = device.createTexture({
label: fTexture,
format: "rgba8unorm",
size: [source.width, source.height],
usage:
GPUTextureUsage.TEXTURE_BINDING |
GPUTextureUsage.COPY_DST |
GPUTextureUsage.RENDER_ATTACHMENT,
});
// Explicitly pass flipY: false - should behave same as omitting it
device.queue.copyExternalImageToTexture(
{ source, flipY: false },
{ texture },
{ width: source.width, height: source.height },
);
const sampler = device.createSampler({
addressModeU: "repeat",
addressModeV: "repeat",
magFilter: "linear",
});

const bindGroup = device.createBindGroup({
layout: pipeline.getBindGroupLayout(0),
entries: [
{ binding: 0, resource: sampler },
{ binding: 1, resource: texture.createView() },
],
});

const renderPassDescriptor: GPURenderPassDescriptor = {
label: "our basic canvas renderPass",
colorAttachments: [
{
view: ctx.getCurrentTexture().createView(),
clearValue: [0.3, 0.3, 0.3, 1],
loadOp: "clear",
storeOp: "store",
},
],
};

const encoder = device.createCommandEncoder({
label: "render quad encoder",
});
const pass = encoder.beginRenderPass(renderPassDescriptor);
pass.setPipeline(pipeline);
pass.setBindGroup(0, bindGroup);
pass.draw(6);
pass.end();

const commandBuffer = encoder.finish();
device.queue.submit([commandBuffer]);
return canvas.getImageData();
});
});
});
},
{},
);
const image = encodeImage(result);
// flipY: false should produce the same result as omitting flipY (f2.png)
// This test catches the bug where std::optional<bool> was checked incorrectly
checkImage(image, "snapshots/f2.png");
});
});
Loading