Skip to content

Commit

Permalink
Add Canvas transparency on iOS (#157)
Browse files Browse the repository at this point in the history
  • Loading branch information
wcandillon authored Oct 19, 2024
1 parent 62dc18d commit 1bc7c5b
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 20 deletions.
8 changes: 3 additions & 5 deletions apps/example/src/Triangle/HelloTriangle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export function HelloTriangle() {
context.configure({
device,
format: presentationFormat,
alphaMode: "opaque",
alphaMode: "premultiplied",
});

const pipeline = device.createRenderPipeline({
Expand Down Expand Up @@ -79,7 +79,8 @@ export function HelloTriangle() {

return (
<View style={style.container}>
<Canvas ref={ref} style={style.webgpu} />
<View style={{ flex: 1, backgroundColor: "#3498db" }} />
<Canvas ref={ref} style={StyleSheet.absoluteFill} />
</View>
);
}
Expand All @@ -88,7 +89,4 @@ const style = StyleSheet.create({
container: {
flex: 1,
},
webgpu: {
flex: 1,
},
});
2 changes: 1 addition & 1 deletion apps/example/src/Triangle/triangle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ fn main(
export const redFragWGSL = `@fragment
fn main() -> @location(0) vec4f {
return vec4(1.0, 0.0, 0.0, 1.0);
}`;
}`;
9 changes: 0 additions & 9 deletions packages/webgpu/cpp/rnwgpu/api/Convertors.h
Original file line number Diff line number Diff line change
Expand Up @@ -280,15 +280,6 @@ class Convertor {
Convert(out.label, in.label);
}

// [[nodiscard]] bool Convert(wgpu::CanvasConfiguration &out,
// const GPUCanvasConfiguration &in) {
// return Convert(out.device, in.device) && Convert(out.format, in.format)
// &&
// Convert(out.usage, in.usage) && Convert(out.viewFormats,
// in.viewFormats) && Convert(out.colorSpace, in.colorSpace) &&
// Convert(out.alphaMode, in.alphaMode);
// }

[[nodiscard]] bool Convert(wgpu::Color &out, const GPUColor &in) {
return Convert(out.r, in.r) && Convert(out.g, in.g) &&
Convert(out.b, in.b) && Convert(out.a, in.a);
Expand Down
11 changes: 6 additions & 5 deletions packages/webgpu/cpp/rnwgpu/api/GPUCanvasContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@ void GPUCanvasContext::configure(
throw std::runtime_error("Error with SurfaceConfiguration");
}
}
if (!conv(surfaceConfiguration.format, configuration->format)) {
throw std::runtime_error("Error with SurfaceConfiguration");
}
if (!conv(surfaceConfiguration.usage, configuration->usage)) {
throw std::runtime_error("Error with SurfaceConfiguration");
if (!conv(surfaceConfiguration.usage, configuration->usage) || !conv(surfaceConfiguration.format, configuration->format)) {
throw std::runtime_error("Error with SurfaceConfiguration");
}

#ifdef __APPLE__
surfaceConfiguration.alphaMode = configuration->alphaMode;
#endif
_surfaceInfo->configure(surfaceConfiguration);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ struct GPUCanvasConfiguration {
std::optional<double> usage; // GPUTextureUsageFlags
std::optional<std::vector<wgpu::TextureFormat>>
viewFormats; // Iterable<GPUTextureFormat>
wgpu::CompositeAlphaMode alphaMode = wgpu::CompositeAlphaMode::Opaque;
};

} // namespace rnwgpu
Expand Down Expand Up @@ -58,6 +59,12 @@ struct JSIConverter<std::shared_ptr<rnwgpu::GPUCanvasConfiguration>> {
prop,
false);
}
if (value.hasProperty(runtime, "alphaMode")) {
auto prop = value.getProperty(runtime, "alphaMode").asString(runtime).utf8(runtime);
if (prop == "premultiplied") {
result->alphaMode = wgpu::CompositeAlphaMode::Premultiplied;
}
}
}

return result;
Expand Down
28 changes: 28 additions & 0 deletions packages/webgpu/src/__tests__/Alpha.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { checkImage, client, encodeImage } from "./setup";

describe("Alpha", () => {
it("Premultiplied Color", async () => {
const result = await client.eval(({ device, ctx, canvas }) => {
const commandEncoder = device.createCommandEncoder();
const textureView = ctx.getCurrentTexture().createView();
const alpha = 0.5;
const renderPassDescriptor: GPURenderPassDescriptor = {
colorAttachments: [
{
view: textureView,
clearValue: [0.3 * alpha, 0.6 * alpha, 1 * alpha, alpha],
loadOp: "clear",
storeOp: "store",
},
],
};

const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
passEncoder.end();
device.queue.submit([commandEncoder.finish()]);
return canvas.getImageData();
});
const image = encodeImage(result);
checkImage(image, "snapshots/semi-opaque-cyan.png");
});
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 1bc7c5b

Please sign in to comment.