diff --git a/lib/gpu/formats.h b/lib/gpu/formats.h index a70d6088890a3..cd9ac858209ca 100644 --- a/lib/gpu/formats.h +++ b/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/lib/gpu/lib/src/formats.dart b/lib/gpu/lib/src/formats.dart index 2bd1b5ddd70cf..ec6e703d90ad4 100644 --- a/lib/gpu/lib/src/formats.dart +++ b/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/lib/gpu/lib/src/render_pass.dart b/lib/gpu/lib/src/render_pass.dart index c3b7ab7814044..942d4a1185558 100644 --- a/lib/gpu/lib/src/render_pass.dart +++ b/lib/gpu/lib/src/render_pass.dart @@ -268,6 +268,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"); @@ -410,6 +414,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/lib/gpu/render_pass.cc b/lib/gpu/render_pass.cc index 068dc68a7528f..5bc1af716aa73 100644 --- a/lib/gpu/render_pass.cc +++ b/lib/gpu/render_pass.cc @@ -570,6 +570,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/lib/gpu/render_pass.h b/lib/gpu/render_pass.h index 89ccf0a55d7f5..df0c2874d24b5 100644 --- a/lib/gpu/render_pass.h +++ b/lib/gpu/render_pass.h @@ -248,6 +248,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/testing/dart/gpu_test.dart b/testing/dart/gpu_test.dart index b3099cf89f5ed..7866376d4c146 100644 --- a/testing/dart/gpu_test.dart +++ b/testing/dart/gpu_test.dart @@ -469,11 +469,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();