diff --git a/engine/src/flutter/lib/gpu/formats.h b/engine/src/flutter/lib/gpu/formats.h index a70d6088890..cd9ac858209 100644 --- a/engine/src/flutter/lib/gpu/formats.h +++ b/engine/src/flutter/lib/gpu/formats.h @@ -522,6 +522,25 @@ constexpr impeller::CullMode ToImpellerCullMode(int value) { return ToImpellerCullMode(static_cast(value)); } +enum class FlutterGPUWindingOrder { + kClockwise, + kCounterClockwise, +}; + +constexpr impeller::WindingOrder ToImpellerWindingOrder( + FlutterGPUWindingOrder value) { + switch (value) { + case FlutterGPUWindingOrder::kClockwise: + return impeller::WindingOrder::kClockwise; + case FlutterGPUWindingOrder::kCounterClockwise: + return impeller::WindingOrder::kCounterClockwise; + } +} + +constexpr impeller::WindingOrder ToImpellerWindingOrder(int value) { + return ToImpellerWindingOrder(static_cast(value)); +} + } // namespace gpu } // namespace flutter diff --git a/engine/src/flutter/lib/gpu/lib/src/formats.dart b/engine/src/flutter/lib/gpu/lib/src/formats.dart index 2bd1b5ddd70..ec6e703d90a 100644 --- a/engine/src/flutter/lib/gpu/lib/src/formats.dart +++ b/engine/src/flutter/lib/gpu/lib/src/formats.dart @@ -141,6 +141,11 @@ enum CullMode { backFace, } +enum WindingOrder { + clockwise, + counterClockwise, +} + enum CompareFunction { /// Comparison test never passes. never, diff --git a/engine/src/flutter/lib/gpu/lib/src/render_pass.dart b/engine/src/flutter/lib/gpu/lib/src/render_pass.dart index 18718bb578e..f6902108cdc 100644 --- a/engine/src/flutter/lib/gpu/lib/src/render_pass.dart +++ b/engine/src/flutter/lib/gpu/lib/src/render_pass.dart @@ -262,6 +262,10 @@ base class RenderPass extends NativeFieldWrapperClass1 { _setCullMode(cullMode.index); } + void setWindingOrder(WindingOrder windingOrder) { + _setWindingOrder(windingOrder.index); + } + void draw() { if (!_draw()) { throw Exception("Failed to append draw"); @@ -416,6 +420,10 @@ base class RenderPass extends NativeFieldWrapperClass1 { symbol: 'InternalFlutterGpu_RenderPass_SetCullMode') external void _setCullMode(int cullMode); + @Native, Int)>( + symbol: 'InternalFlutterGpu_RenderPass_SetWindingOrder') + external void _setWindingOrder(int windingOrder); + @Native)>( symbol: 'InternalFlutterGpu_RenderPass_Draw') external bool _draw(); diff --git a/engine/src/flutter/lib/gpu/render_pass.cc b/engine/src/flutter/lib/gpu/render_pass.cc index 69eec79a931..26fcf5435ec 100644 --- a/engine/src/flutter/lib/gpu/render_pass.cc +++ b/engine/src/flutter/lib/gpu/render_pass.cc @@ -567,6 +567,15 @@ void InternalFlutterGpu_RenderPass_SetCullMode( pipeline_descriptor.SetCullMode(flutter::gpu::ToImpellerCullMode(cull_mode)); } +void InternalFlutterGpu_RenderPass_SetWindingOrder( + flutter::gpu::RenderPass* wrapper, + int winding_order) { + impeller::PipelineDescriptor& pipeline_descriptor = + wrapper->GetPipelineDescriptor(); + pipeline_descriptor.SetWindingOrder( + flutter::gpu::ToImpellerWindingOrder(winding_order)); +} + bool InternalFlutterGpu_RenderPass_Draw(flutter::gpu::RenderPass* wrapper) { return wrapper->Draw(); } diff --git a/engine/src/flutter/lib/gpu/render_pass.h b/engine/src/flutter/lib/gpu/render_pass.h index 94f6627a7ba..4069d37537b 100644 --- a/engine/src/flutter/lib/gpu/render_pass.h +++ b/engine/src/flutter/lib/gpu/render_pass.h @@ -251,6 +251,11 @@ extern void InternalFlutterGpu_RenderPass_SetCullMode( flutter::gpu::RenderPass* wrapper, int cull_mode); +FLUTTER_GPU_EXPORT +extern void InternalFlutterGpu_RenderPass_SetWindingOrder( + flutter::gpu::RenderPass* wrapper, + int winding_order); + FLUTTER_GPU_EXPORT extern bool InternalFlutterGpu_RenderPass_Draw( flutter::gpu::RenderPass* wrapper); diff --git a/engine/src/flutter/testing/dart/gpu_test.dart b/engine/src/flutter/testing/dart/gpu_test.dart index 05ba001b635..e8ead29aad0 100644 --- a/engine/src/flutter/testing/dart/gpu_test.dart +++ b/engine/src/flutter/testing/dart/gpu_test.dart @@ -479,11 +479,21 @@ void main() async { state.renderPass.draw(); } + // Draw the green rectangle. + // Defaults to clockwise winding order. So frontface culling should not + // impact the green triangle. state.renderPass.setCullMode(gpu.CullMode.frontFace); drawTriangle(Colors.lime); + + // Backface cull a red triangle. state.renderPass.setCullMode(gpu.CullMode.backFace); drawTriangle(Colors.red); + // Invert the winding mode and frontface cull a red rectangle. + state.renderPass.setWindingOrder(gpu.WindingOrder.counterClockwise); + state.renderPass.setCullMode(gpu.CullMode.frontFace); + drawTriangle(Colors.red); + state.commandBuffer.submit(); final ui.Image image = state.renderTexture.asImage();