[Flutter GPU] Add CullMode. (flutter/engine#55409)
Part of https://github.com/flutter/flutter/issues/155636. New golden `flutter_gpu_test_cull_mode` will draw a red triangle if the CullMode isn't working: 
This commit is contained in:
parent
9f1cee211c
commit
e496b1ed26
@ -501,6 +501,27 @@ constexpr impeller::StencilOperation ToImpellerStencilOperation(int value) {
|
|||||||
static_cast<FlutterGPUStencilOperation>(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 gpu
|
||||||
} // namespace flutter
|
} // namespace flutter
|
||||||
|
|
||||||
|
@ -135,6 +135,12 @@ enum PrimitiveType {
|
|||||||
point,
|
point,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum CullMode {
|
||||||
|
none,
|
||||||
|
frontFace,
|
||||||
|
backFace,
|
||||||
|
}
|
||||||
|
|
||||||
enum CompareFunction {
|
enum CompareFunction {
|
||||||
/// Comparison test never passes.
|
/// Comparison test never passes.
|
||||||
never,
|
never,
|
||||||
|
@ -264,6 +264,10 @@ base class RenderPass extends NativeFieldWrapperClass1 {
|
|||||||
targetFace.index);
|
targetFace.index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setCullMode(CullMode cullMode) {
|
||||||
|
_setCullMode(cullMode.index);
|
||||||
|
}
|
||||||
|
|
||||||
void draw() {
|
void draw() {
|
||||||
if (!_draw()) {
|
if (!_draw()) {
|
||||||
throw Exception("Failed to append draw");
|
throw Exception("Failed to append draw");
|
||||||
@ -402,6 +406,10 @@ base class RenderPass extends NativeFieldWrapperClass1 {
|
|||||||
int writeMask,
|
int writeMask,
|
||||||
int target_face);
|
int target_face);
|
||||||
|
|
||||||
|
@Native<Void Function(Pointer<Void>, Int)>(
|
||||||
|
symbol: 'InternalFlutterGpu_RenderPass_SetCullMode')
|
||||||
|
external void _setCullMode(int cullMode);
|
||||||
|
|
||||||
@Native<Bool Function(Pointer<Void>)>(
|
@Native<Bool Function(Pointer<Void>)>(
|
||||||
symbol: 'InternalFlutterGpu_RenderPass_Draw')
|
symbol: 'InternalFlutterGpu_RenderPass_Draw')
|
||||||
external bool _draw();
|
external bool _draw();
|
||||||
|
@ -76,6 +76,10 @@ impeller::VertexBuffer& RenderPass::GetVertexBuffer() {
|
|||||||
return vertex_buffer_;
|
return vertex_buffer_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impeller::PipelineDescriptor& RenderPass::GetPipelineDescriptor() {
|
||||||
|
return pipeline_descriptor_;
|
||||||
|
}
|
||||||
|
|
||||||
bool RenderPass::Begin(flutter::gpu::CommandBuffer& command_buffer) {
|
bool RenderPass::Begin(flutter::gpu::CommandBuffer& command_buffer) {
|
||||||
render_pass_ =
|
render_pass_ =
|
||||||
command_buffer.GetCommandBuffer()->CreateRenderPass(render_target_);
|
command_buffer.GetCommandBuffer()->CreateRenderPass(render_target_);
|
||||||
@ -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) {
|
bool InternalFlutterGpu_RenderPass_Draw(flutter::gpu::RenderPass* wrapper) {
|
||||||
return wrapper->Draw();
|
return wrapper->Draw();
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,8 @@ class RenderPass : public RefCountedDartWrappable<RenderPass> {
|
|||||||
|
|
||||||
impeller::VertexBuffer& GetVertexBuffer();
|
impeller::VertexBuffer& GetVertexBuffer();
|
||||||
|
|
||||||
|
impeller::PipelineDescriptor& GetPipelineDescriptor();
|
||||||
|
|
||||||
bool Begin(flutter::gpu::CommandBuffer& command_buffer);
|
bool Begin(flutter::gpu::CommandBuffer& command_buffer);
|
||||||
|
|
||||||
void SetPipeline(fml::RefPtr<RenderPipeline> pipeline);
|
void SetPipeline(fml::RefPtr<RenderPipeline> pipeline);
|
||||||
@ -241,6 +243,11 @@ extern void InternalFlutterGpu_RenderPass_SetStencilConfig(
|
|||||||
int write_mask,
|
int write_mask,
|
||||||
int target);
|
int target);
|
||||||
|
|
||||||
|
FLUTTER_GPU_EXPORT
|
||||||
|
extern void InternalFlutterGpu_RenderPass_SetCullMode(
|
||||||
|
flutter::gpu::RenderPass* wrapper,
|
||||||
|
int cull_mode);
|
||||||
|
|
||||||
FLUTTER_GPU_EXPORT
|
FLUTTER_GPU_EXPORT
|
||||||
extern bool InternalFlutterGpu_RenderPass_Draw(
|
extern bool InternalFlutterGpu_RenderPass_Draw(
|
||||||
flutter::gpu::RenderPass* wrapper);
|
flutter::gpu::RenderPass* wrapper);
|
||||||
|
@ -11,6 +11,7 @@ import 'dart:typed_data';
|
|||||||
import 'dart:ui' as ui;
|
import 'dart:ui' as ui;
|
||||||
|
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
import 'package:vector_math/vector_math.dart';
|
||||||
|
|
||||||
import '../../lib/gpu/lib/gpu.dart' as gpu;
|
import '../../lib/gpu/lib/gpu.dart' as gpu;
|
||||||
|
|
||||||
@ -21,6 +22,16 @@ ByteData float32(List<double> values) {
|
|||||||
return Float32List.fromList(values).buffer.asByteData();
|
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() {
|
gpu.RenderPipeline createUnlitRenderPipeline() {
|
||||||
final gpu.ShaderLibrary? library =
|
final gpu.ShaderLibrary? library =
|
||||||
gpu.ShaderLibrary.fromAsset('test.shaderbundle');
|
gpu.ShaderLibrary.fromAsset('test.shaderbundle');
|
||||||
@ -425,4 +436,47 @@ void main() async {
|
|||||||
await comparer.addGoldenImage(
|
await comparer.addGoldenImage(
|
||||||
image, 'flutter_gpu_test_triangle_stencil.png');
|
image, 'flutter_gpu_test_triangle_stencil.png');
|
||||||
}, skip: !impellerEnabled);
|
}, 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);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user