Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
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
21 changes: 21 additions & 0 deletions lib/gpu/formats.h
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,27 @@ constexpr impeller::StencilOperation ToImpellerStencilOperation(int value) {
static_cast<FlutterGPUStencilOperation>(value));
}

enum class FlutterGPUCullMode {
kNone,
kFrontFace,
kBackFace,
};

constexpr impeller::CullMode ToImpellerCullMode(FlutterGPUCullMode value) {
switch (value) {
case FlutterGPUCullMode::kNone:
return impeller::CullMode::kNone;
case FlutterGPUCullMode::kFrontFace:
return impeller::CullMode::kFrontFace;
case FlutterGPUCullMode::kBackFace:
return impeller::CullMode::kBackFace;
}
}

constexpr impeller::CullMode ToImpellerCullMode(int value) {
return ToImpellerCullMode(static_cast<FlutterGPUCullMode>(value));
}

} // namespace gpu
} // namespace flutter

Expand Down
6 changes: 6 additions & 0 deletions lib/gpu/lib/src/formats.dart
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,12 @@ enum PrimitiveType {
point,
}

enum CullMode {
none,
frontFace,
backFace,
}

enum CompareFunction {
/// Comparison test never passes.
never,
Expand Down
8 changes: 8 additions & 0 deletions lib/gpu/lib/src/render_pass.dart
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,10 @@ base class RenderPass extends NativeFieldWrapperClass1 {
targetFace.index);
}

void setCullMode(CullMode cullMode) {
_setCullMode(cullMode.index);
}

void draw() {
if (!_draw()) {
throw Exception("Failed to append draw");
Expand Down Expand Up @@ -402,6 +406,10 @@ base class RenderPass extends NativeFieldWrapperClass1 {
int writeMask,
int target_face);

@Native<Void Function(Pointer<Void>, Int)>(
symbol: 'InternalFlutterGpu_RenderPass_SetCullMode')
external void _setCullMode(int cullMode);

@Native<Bool Function(Pointer<Void>)>(
symbol: 'InternalFlutterGpu_RenderPass_Draw')
external bool _draw();
Expand Down
12 changes: 12 additions & 0 deletions lib/gpu/render_pass.cc
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ impeller::VertexBuffer& RenderPass::GetVertexBuffer() {
return vertex_buffer_;
}

impeller::PipelineDescriptor& RenderPass::GetPipelineDescriptor() {
return pipeline_descriptor_;
}

bool RenderPass::Begin(flutter::gpu::CommandBuffer& command_buffer) {
render_pass_ =
command_buffer.GetCommandBuffer()->CreateRenderPass(render_target_);
Expand Down Expand Up @@ -558,6 +562,14 @@ void InternalFlutterGpu_RenderPass_SetStencilConfig(
}
}

void InternalFlutterGpu_RenderPass_SetCullMode(
flutter::gpu::RenderPass* wrapper,
int cull_mode) {
impeller::PipelineDescriptor& pipeline_descriptor =
wrapper->GetPipelineDescriptor();
pipeline_descriptor.SetCullMode(flutter::gpu::ToImpellerCullMode(cull_mode));
}

bool InternalFlutterGpu_RenderPass_Draw(flutter::gpu::RenderPass* wrapper) {
return wrapper->Draw();
}
7 changes: 7 additions & 0 deletions lib/gpu/render_pass.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ class RenderPass : public RefCountedDartWrappable<RenderPass> {

impeller::VertexBuffer& GetVertexBuffer();

impeller::PipelineDescriptor& GetPipelineDescriptor();

bool Begin(flutter::gpu::CommandBuffer& command_buffer);

void SetPipeline(fml::RefPtr<RenderPipeline> pipeline);
Expand Down Expand Up @@ -241,6 +243,11 @@ extern void InternalFlutterGpu_RenderPass_SetStencilConfig(
int write_mask,
int target);

FLUTTER_GPU_EXPORT
extern void InternalFlutterGpu_RenderPass_SetCullMode(
flutter::gpu::RenderPass* wrapper,
int cull_mode);

FLUTTER_GPU_EXPORT
extern bool InternalFlutterGpu_RenderPass_Draw(
flutter::gpu::RenderPass* wrapper);
Expand Down
54 changes: 54 additions & 0 deletions testing/dart/gpu_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import 'dart:typed_data';
import 'dart:ui' as ui;

import 'package:test/test.dart';
import 'package:vector_math/vector_math.dart';

import '../../lib/gpu/lib/gpu.dart' as gpu;

Expand All @@ -21,6 +22,16 @@ ByteData float32(List<double> values) {
return Float32List.fromList(values).buffer.asByteData();
}

ByteData unlitUBO(Matrix4 mvp, Vector4 color) {
return float32(<double>[
mvp[0], mvp[1], mvp[2], mvp[3], //
mvp[4], mvp[5], mvp[6], mvp[7], //
mvp[8], mvp[9], mvp[10], mvp[11], //
mvp[12], mvp[13], mvp[14], mvp[15], //
color.r, color.g, color.b, color.a,
]);
}

gpu.RenderPipeline createUnlitRenderPipeline() {
final gpu.ShaderLibrary? library =
gpu.ShaderLibrary.fromAsset('test.shaderbundle');
Expand Down Expand Up @@ -425,4 +436,47 @@ void main() async {
await comparer.addGoldenImage(
image, 'flutter_gpu_test_triangle_stencil.png');
}, skip: !impellerEnabled);

test('Drawing respects cull mode', () async {
final state = createSimpleRenderPass();

final gpu.RenderPipeline pipeline = createUnlitRenderPipeline();
state.renderPass.bindPipeline(pipeline);

state.renderPass.setColorBlendEnable(true);
state.renderPass.setColorBlendEquation(gpu.ColorBlendEquation());

final gpu.HostBuffer transients = gpu.gpuContext.createHostBuffer();
// Counter-clockwise triangle.
final List<double> triangle = [
-0.5, 0.5, //
0.0, -0.5, //
0.5, 0.5, //
];
final gpu.BufferView vertices = transients.emplace(float32(triangle));

void drawTriangle(Vector4 color) {
final gpu.BufferView vertInfoUboFront =
transients.emplace(unlitUBO(Matrix4.identity(), color));

final gpu.UniformSlot vertInfo =
pipeline.vertexShader.getUniformSlot('VertInfo');
// TODO(bdero): Overwrite bindings with the same slot so we don't need to clear.
// https://github.com/flutter/flutter/issues/155335
state.renderPass.clearBindings();
state.renderPass.bindVertexBuffer(vertices, 3);
state.renderPass.bindUniform(vertInfo, vertInfoUboFront);
state.renderPass.draw();
}

state.renderPass.setCullMode(gpu.CullMode.frontFace);
drawTriangle(Colors.lime);
state.renderPass.setCullMode(gpu.CullMode.backFace);
drawTriangle(Colors.red);

state.commandBuffer.submit();

final ui.Image image = state.renderTexture.asImage();
await comparer.addGoldenImage(image, 'flutter_gpu_test_cull_mode.png');
}, skip: !impellerEnabled);
}