From 7cb953142068e831943ffb488e57c11dbe1c677d Mon Sep 17 00:00:00 2001 From: Athul Joseph Date: Fri, 1 Nov 2024 17:55:30 +0530 Subject: [PATCH 1/5] Added support to set scissor. --- lib/gpu/lib/src/render_pass.dart | 21 +++++++++++++++ lib/gpu/render_pass.cc | 6 +++++ lib/gpu/render_pass.h | 9 +++++++ testing/dart/gpu_test.dart | 46 ++++++++++++++++++++++++++++++++ 4 files changed, 82 insertions(+) diff --git a/lib/gpu/lib/src/render_pass.dart b/lib/gpu/lib/src/render_pass.dart index 15389579b7f6c..62e042b974889 100644 --- a/lib/gpu/lib/src/render_pass.dart +++ b/lib/gpu/lib/src/render_pass.dart @@ -150,6 +150,12 @@ base class SamplerOptions { SamplerAddressMode heightAddressMode; } +base class Scissor { + Scissor({this.x = 0, this.y = 0, this.width = 0, this.height = 0}); + + int x, y, width, height; +} + base class RenderTarget { const RenderTarget( {this.colorAttachments = const [], @@ -214,6 +220,9 @@ base class RenderPass extends NativeFieldWrapperClass1 { if (error != null) { throw Exception(error); } + + final texture = renderTarget.depthStencilAttachment!.texture; + _setScissor(0, 0, texture.width, texture.height); } error = _begin(commandBuffer); if (error != null) { @@ -326,6 +335,10 @@ base class RenderPass extends NativeFieldWrapperClass1 { targetFace.index); } + void setScissor(Scissor scissor) { + _setScissor(scissor.x, scissor.y, scissor.width, scissor.height); + } + void setCullMode(CullMode cullMode) { _setCullMode(cullMode.index); } @@ -477,6 +490,14 @@ base class RenderPass extends NativeFieldWrapperClass1 { int readMask, int writeMask, int target_face); + + @Native, Int, Int, Int, Int)>( + symbol: 'InternalFlutterGpu_RenderPass_SetScissor') + external void _setScissor( + int x, + int y, + int width, + int height); @Native, Int)>( symbol: 'InternalFlutterGpu_RenderPass_SetCullMode') diff --git a/lib/gpu/render_pass.cc b/lib/gpu/render_pass.cc index 637f7446e5266..dc7f1a4850075 100644 --- a/lib/gpu/render_pass.cc +++ b/lib/gpu/render_pass.cc @@ -206,6 +206,7 @@ bool RenderPass::Draw() { render_pass_->SetElementCount(element_count); render_pass_->SetStencilReference(stencil_reference); + render_pass_->SetScissor(scissor); bool result = render_pass_->Draw().ok(); @@ -536,6 +537,11 @@ void InternalFlutterGpu_RenderPass_SetStencilReference( wrapper->stencil_reference = static_cast(stencil_reference); } +void InternalFlutterGpu_RenderPass_SetScissor( + flutter::gpu::RenderPass* wrapper, int x, int y, int width, int height) { + wrapper->scissor = impeller::TRect::MakeXYWH(x, y, width, height); +} + void InternalFlutterGpu_RenderPass_SetStencilConfig( flutter::gpu::RenderPass* wrapper, int stencil_compare_operation, diff --git a/lib/gpu/render_pass.h b/lib/gpu/render_pass.h index 1b33a5ebaef3d..1bb93d6155fff 100644 --- a/lib/gpu/render_pass.h +++ b/lib/gpu/render_pass.h @@ -74,6 +74,7 @@ class RenderPass : public RefCountedDartWrappable { size_t element_count = 0; uint32_t stencil_reference = 0; + impeller::TRect scissor; // Helper flag to determine whether the vertex_count should override the // element count. The index count takes precedent. @@ -234,6 +235,14 @@ extern void InternalFlutterGpu_RenderPass_SetStencilConfig( int write_mask, int target); +FLUTTER_GPU_EXPORT +extern void InternalFlutterGpu_RenderPass_SetScissor( + flutter::gpu::RenderPass* wrapper, + int x, + int y, + int width, + int height); + FLUTTER_GPU_EXPORT extern void InternalFlutterGpu_RenderPass_SetCullMode( flutter::gpu::RenderPass* wrapper, diff --git a/testing/dart/gpu_test.dart b/testing/dart/gpu_test.dart index c1d45183f9c79..21f4cb0880ef1 100644 --- a/testing/dart/gpu_test.dart +++ b/testing/dart/gpu_test.dart @@ -736,4 +736,50 @@ void main() async { await comparer.addGoldenImage( image, 'flutter_gpu_test_hexgon_line_strip.png'); }, skip: !impellerEnabled); + + // Renders the middle part triangle using scissor. + test('Can render portion of the triangle using scissor', () async { + final state = createSimpleRenderPass(); + + final gpu.RenderPipeline pipeline = createUnlitRenderPipeline(); + state.renderPass.bindPipeline(pipeline); + + // Configure blending with defaults (just to test the bindings). + state.renderPass.setColorBlendEnable(true); + state.renderPass.setColorBlendEquation(gpu.ColorBlendEquation()); + + // Set primitive type. + state.renderPass.setPrimitiveType(gpu.PrimitiveType.triangle); + + // Set scissor. + state.renderPass.setScissor(gpu.Scissor(x: 25, y: 0, width: 50, height: 100)); + + final gpu.HostBuffer transients = gpu.gpuContext.createHostBuffer(); + final gpu.BufferView vertices = transients.emplace(float32([ + -1.0, + -1.0, + 0.0, + 1.0, + 1.0, + -1.0])); + final gpu.BufferView vertInfoData = transients.emplace(float32([ + 1, 0, 0, 0, // mvp + 0, 1, 0, 0, // mvp + 0, 0, 1, 0, // mvp + 0, 0, 0, 1, // mvp + 0, 1, 0, 1, // color + ])); + state.renderPass.bindVertexBuffer(vertices, 3); + + final gpu.UniformSlot vertInfo = + pipeline.vertexShader.getUniformSlot('VertInfo'); + state.renderPass.bindUniform(vertInfo, vertInfoData); + state.renderPass.draw(); + + state.commandBuffer.submit(); + + final ui.Image image = state.renderTexture.asImage(); + await comparer.addGoldenImage( + image, 'flutter_gpu_test_scissor.png'); + }, skip: !impellerEnabled); } From 64f51e31ce496ff55657c78af754cfee0f6ff1d8 Mon Sep 17 00:00:00 2001 From: Athul Joseph Date: Fri, 1 Nov 2024 18:00:07 +0530 Subject: [PATCH 2/5] Added support to set scissor. --- lib/gpu/lib/src/render_pass.dart | 2 +- lib/gpu/render_pass.cc | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/gpu/lib/src/render_pass.dart b/lib/gpu/lib/src/render_pass.dart index 62e042b974889..34c67d88a72b4 100644 --- a/lib/gpu/lib/src/render_pass.dart +++ b/lib/gpu/lib/src/render_pass.dart @@ -490,7 +490,7 @@ base class RenderPass extends NativeFieldWrapperClass1 { int readMask, int writeMask, int target_face); - + @Native, Int, Int, Int, Int)>( symbol: 'InternalFlutterGpu_RenderPass_SetScissor') external void _setScissor( diff --git a/lib/gpu/render_pass.cc b/lib/gpu/render_pass.cc index dc7f1a4850075..5b9292d188c9d 100644 --- a/lib/gpu/render_pass.cc +++ b/lib/gpu/render_pass.cc @@ -537,8 +537,11 @@ void InternalFlutterGpu_RenderPass_SetStencilReference( wrapper->stencil_reference = static_cast(stencil_reference); } -void InternalFlutterGpu_RenderPass_SetScissor( - flutter::gpu::RenderPass* wrapper, int x, int y, int width, int height) { +void InternalFlutterGpu_RenderPass_SetScissor(flutter::gpu::RenderPass* wrapper, + int x, + int y, + int width, + int height) { wrapper->scissor = impeller::TRect::MakeXYWH(x, y, width, height); } From 6cb6c0b9ca731bb90d4852f39e12369cc3baecc0 Mon Sep 17 00:00:00 2001 From: AthulJoseph <55750689+AthulJoseph27@users.noreply.github.com> Date: Fri, 1 Nov 2024 21:24:24 +0530 Subject: [PATCH 3/5] Update gpu_test.dart --- testing/dart/gpu_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/dart/gpu_test.dart b/testing/dart/gpu_test.dart index 21f4cb0880ef1..b3e982fa77823 100644 --- a/testing/dart/gpu_test.dart +++ b/testing/dart/gpu_test.dart @@ -752,7 +752,7 @@ void main() async { state.renderPass.setPrimitiveType(gpu.PrimitiveType.triangle); // Set scissor. - state.renderPass.setScissor(gpu.Scissor(x: 25, y: 0, width: 50, height: 100)); + state.renderPass.setScissor(gpu.Scissor(x: 25, width: 50, height: 100)); final gpu.HostBuffer transients = gpu.gpuContext.createHostBuffer(); final gpu.BufferView vertices = transients.emplace(float32([ From 5f661528cfefb0611d0452afae4586929297e44c Mon Sep 17 00:00:00 2001 From: AthulJoseph <55750689+AthulJoseph27@users.noreply.github.com> Date: Wed, 13 Nov 2024 18:32:53 +0530 Subject: [PATCH 4/5] Update render_pass.dart --- lib/gpu/lib/src/render_pass.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/gpu/lib/src/render_pass.dart b/lib/gpu/lib/src/render_pass.dart index 1d3e0a164d050..6dd60ab548a85 100644 --- a/lib/gpu/lib/src/render_pass.dart +++ b/lib/gpu/lib/src/render_pass.dart @@ -339,7 +339,10 @@ base class RenderPass extends NativeFieldWrapperClass1 { } void setScissor(Scissor scissor) { - scissor._validate(); + assert(() { + scissor._validate(); + return true; + }()); _setScissor(scissor.x, scissor.y, scissor.width, scissor.height); } From 2d0d884971a780c4da6bdbba37267f99999e3b31 Mon Sep 17 00:00:00 2001 From: Athul Joseph Date: Wed, 20 Nov 2024 08:48:50 +0530 Subject: [PATCH 5/5] amend --- testing/dart/gpu_test.dart | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/testing/dart/gpu_test.dart b/testing/dart/gpu_test.dart index b3e982fa77823..1317a5fbb4f6e 100644 --- a/testing/dart/gpu_test.dart +++ b/testing/dart/gpu_test.dart @@ -782,4 +782,32 @@ void main() async { await comparer.addGoldenImage( image, 'flutter_gpu_test_scissor.png'); }, skip: !impellerEnabled); + + test('RenderPass.setScissor doesnt throw for valid values', + () async { + final state = createSimpleRenderPass(); + + state.renderPass.setScissor(gpu.Scissor(x: 25, width: 50, height: 100)); + state.renderPass.setScissor(gpu.Scissor(width: 50, height: 100)); + }, skip: !impellerEnabled); + + test('RenderPass.setScissor throws for invalid values', () async { + final state = createSimpleRenderPass(); + + try { + state.renderPass.setScissor(gpu.Scissor(x: -1, width: 50, height: 100)); + fail('Exception not thrown for invalid scissor.'); + } catch (e) { + expect(e.toString(), + contains('Invalid values for scissor. All values should be positive.')); + } + + try { + state.renderPass.setScissor(gpu.Scissor(width: 50, height: -100)); + fail('Exception not thrown for invalid scissor.'); + } catch (e) { + expect(e.toString(), + contains('Invalid values for scissor. All values should be positive.')); + } + }, skip: !impellerEnabled); }