diff --git a/apps/example/src/Triangle/HelloTriangle.tsx b/apps/example/src/Triangle/HelloTriangle.tsx index ca753b82..715da40a 100644 --- a/apps/example/src/Triangle/HelloTriangle.tsx +++ b/apps/example/src/Triangle/HelloTriangle.tsx @@ -25,7 +25,7 @@ export function HelloTriangle() { context.configure({ device, format: presentationFormat, - alphaMode: "opaque", + alphaMode: "premultiplied", }); const pipeline = device.createRenderPipeline({ @@ -79,7 +79,8 @@ export function HelloTriangle() { return ( - + + ); } @@ -88,7 +89,4 @@ const style = StyleSheet.create({ container: { flex: 1, }, - webgpu: { - flex: 1, - }, }); diff --git a/apps/example/src/Triangle/triangle.ts b/apps/example/src/Triangle/triangle.ts index 3981386b..f4f6bc98 100644 --- a/apps/example/src/Triangle/triangle.ts +++ b/apps/example/src/Triangle/triangle.ts @@ -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); -}`; +}`; \ No newline at end of file diff --git a/packages/webgpu/cpp/rnwgpu/api/Convertors.h b/packages/webgpu/cpp/rnwgpu/api/Convertors.h index e35ea6f3..537e3a7b 100644 --- a/packages/webgpu/cpp/rnwgpu/api/Convertors.h +++ b/packages/webgpu/cpp/rnwgpu/api/Convertors.h @@ -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); diff --git a/packages/webgpu/cpp/rnwgpu/api/GPUCanvasContext.cpp b/packages/webgpu/cpp/rnwgpu/api/GPUCanvasContext.cpp index 48e9ff08..e76f1622 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPUCanvasContext.cpp +++ b/packages/webgpu/cpp/rnwgpu/api/GPUCanvasContext.cpp @@ -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); } diff --git a/packages/webgpu/cpp/rnwgpu/api/descriptors/GPUCanvasConfiguration.h b/packages/webgpu/cpp/rnwgpu/api/descriptors/GPUCanvasConfiguration.h index 22af9c68..b4ba407c 100644 --- a/packages/webgpu/cpp/rnwgpu/api/descriptors/GPUCanvasConfiguration.h +++ b/packages/webgpu/cpp/rnwgpu/api/descriptors/GPUCanvasConfiguration.h @@ -21,6 +21,7 @@ struct GPUCanvasConfiguration { std::optional usage; // GPUTextureUsageFlags std::optional> viewFormats; // Iterable + wgpu::CompositeAlphaMode alphaMode = wgpu::CompositeAlphaMode::Opaque; }; } // namespace rnwgpu @@ -58,6 +59,12 @@ struct JSIConverter> { 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; diff --git a/packages/webgpu/src/__tests__/Alpha.spec.ts b/packages/webgpu/src/__tests__/Alpha.spec.ts new file mode 100644 index 00000000..bc83e934 --- /dev/null +++ b/packages/webgpu/src/__tests__/Alpha.spec.ts @@ -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"); + }); +}); diff --git a/packages/webgpu/src/__tests__/snapshots/semi-opaque-cyan.png b/packages/webgpu/src/__tests__/snapshots/semi-opaque-cyan.png new file mode 100644 index 00000000..e05b04c3 Binary files /dev/null and b/packages/webgpu/src/__tests__/snapshots/semi-opaque-cyan.png differ