Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 523d381

Browse files
[Flutter GPU] Added support to set Scissor. (#56302)
Added support to set scissors. This resolves issue #157199
1 parent 5f88ef6 commit 523d381

File tree

4 files changed

+123
-0
lines changed

4 files changed

+123
-0
lines changed

lib/gpu/lib/src/render_pass.dart

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,18 @@ base class SamplerOptions {
150150
SamplerAddressMode heightAddressMode;
151151
}
152152

153+
base class Scissor {
154+
Scissor({this.x = 0, this.y = 0, this.width = 0, this.height = 0});
155+
156+
int x, y, width, height;
157+
158+
void _validate() {
159+
if (x < 0 || y < 0 || width < 0 || height < 0) {
160+
throw Exception("Invalid values for scissor. All values should be positive.");
161+
}
162+
}
163+
}
164+
153165
base class RenderTarget {
154166
const RenderTarget(
155167
{this.colorAttachments = const <ColorAttachment>[],
@@ -326,6 +338,14 @@ base class RenderPass extends NativeFieldWrapperClass1 {
326338
targetFace.index);
327339
}
328340

341+
void setScissor(Scissor scissor) {
342+
assert(() {
343+
scissor._validate();
344+
return true;
345+
}());
346+
_setScissor(scissor.x, scissor.y, scissor.width, scissor.height);
347+
}
348+
329349
void setCullMode(CullMode cullMode) {
330350
_setCullMode(cullMode.index);
331351
}
@@ -478,6 +498,14 @@ base class RenderPass extends NativeFieldWrapperClass1 {
478498
int writeMask,
479499
int target_face);
480500

501+
@Native<Void Function(Pointer<Void>, Int, Int, Int, Int)>(
502+
symbol: 'InternalFlutterGpu_RenderPass_SetScissor')
503+
external void _setScissor(
504+
int x,
505+
int y,
506+
int width,
507+
int height);
508+
481509
@Native<Void Function(Pointer<Void>, Int)>(
482510
symbol: 'InternalFlutterGpu_RenderPass_SetCullMode')
483511
external void _setCullMode(int cullMode);

lib/gpu/render_pass.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,10 @@ bool RenderPass::Draw() {
207207

208208
render_pass_->SetStencilReference(stencil_reference);
209209

210+
if (scissor.has_value()) {
211+
render_pass_->SetScissor(scissor.value());
212+
}
213+
210214
bool result = render_pass_->Draw().ok();
211215

212216
return result;
@@ -536,6 +540,14 @@ void InternalFlutterGpu_RenderPass_SetStencilReference(
536540
wrapper->stencil_reference = static_cast<uint32_t>(stencil_reference);
537541
}
538542

543+
void InternalFlutterGpu_RenderPass_SetScissor(flutter::gpu::RenderPass* wrapper,
544+
int x,
545+
int y,
546+
int width,
547+
int height) {
548+
wrapper->scissor = impeller::TRect<int64_t>::MakeXYWH(x, y, width, height);
549+
}
550+
539551
void InternalFlutterGpu_RenderPass_SetStencilConfig(
540552
flutter::gpu::RenderPass* wrapper,
541553
int stencil_compare_operation,

lib/gpu/render_pass.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ class RenderPass : public RefCountedDartWrappable<RenderPass> {
7474
size_t element_count = 0;
7575

7676
uint32_t stencil_reference = 0;
77+
std::optional<impeller::TRect<int64_t>> scissor;
7778

7879
// Helper flag to determine whether the vertex_count should override the
7980
// element count. The index count takes precedent.
@@ -234,6 +235,14 @@ extern void InternalFlutterGpu_RenderPass_SetStencilConfig(
234235
int write_mask,
235236
int target);
236237

238+
FLUTTER_GPU_EXPORT
239+
extern void InternalFlutterGpu_RenderPass_SetScissor(
240+
flutter::gpu::RenderPass* wrapper,
241+
int x,
242+
int y,
243+
int width,
244+
int height);
245+
237246
FLUTTER_GPU_EXPORT
238247
extern void InternalFlutterGpu_RenderPass_SetCullMode(
239248
flutter::gpu::RenderPass* wrapper,

testing/dart/gpu_test.dart

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -736,4 +736,78 @@ void main() async {
736736
await comparer.addGoldenImage(
737737
image, 'flutter_gpu_test_hexgon_line_strip.png');
738738
}, skip: !impellerEnabled);
739+
740+
// Renders the middle part triangle using scissor.
741+
test('Can render portion of the triangle using scissor', () async {
742+
final state = createSimpleRenderPass();
743+
744+
final gpu.RenderPipeline pipeline = createUnlitRenderPipeline();
745+
state.renderPass.bindPipeline(pipeline);
746+
747+
// Configure blending with defaults (just to test the bindings).
748+
state.renderPass.setColorBlendEnable(true);
749+
state.renderPass.setColorBlendEquation(gpu.ColorBlendEquation());
750+
751+
// Set primitive type.
752+
state.renderPass.setPrimitiveType(gpu.PrimitiveType.triangle);
753+
754+
// Set scissor.
755+
state.renderPass.setScissor(gpu.Scissor(x: 25, width: 50, height: 100));
756+
757+
final gpu.HostBuffer transients = gpu.gpuContext.createHostBuffer();
758+
final gpu.BufferView vertices = transients.emplace(float32(<double>[
759+
-1.0,
760+
-1.0,
761+
0.0,
762+
1.0,
763+
1.0,
764+
-1.0]));
765+
final gpu.BufferView vertInfoData = transients.emplace(float32(<double>[
766+
1, 0, 0, 0, // mvp
767+
0, 1, 0, 0, // mvp
768+
0, 0, 1, 0, // mvp
769+
0, 0, 0, 1, // mvp
770+
0, 1, 0, 1, // color
771+
]));
772+
state.renderPass.bindVertexBuffer(vertices, 3);
773+
774+
final gpu.UniformSlot vertInfo =
775+
pipeline.vertexShader.getUniformSlot('VertInfo');
776+
state.renderPass.bindUniform(vertInfo, vertInfoData);
777+
state.renderPass.draw();
778+
779+
state.commandBuffer.submit();
780+
781+
final ui.Image image = state.renderTexture.asImage();
782+
await comparer.addGoldenImage(
783+
image, 'flutter_gpu_test_scissor.png');
784+
}, skip: !impellerEnabled);
785+
786+
test('RenderPass.setScissor doesnt throw for valid values',
787+
() async {
788+
final state = createSimpleRenderPass();
789+
790+
state.renderPass.setScissor(gpu.Scissor(x: 25, width: 50, height: 100));
791+
state.renderPass.setScissor(gpu.Scissor(width: 50, height: 100));
792+
}, skip: !impellerEnabled);
793+
794+
test('RenderPass.setScissor throws for invalid values', () async {
795+
final state = createSimpleRenderPass();
796+
797+
try {
798+
state.renderPass.setScissor(gpu.Scissor(x: -1, width: 50, height: 100));
799+
fail('Exception not thrown for invalid scissor.');
800+
} catch (e) {
801+
expect(e.toString(),
802+
contains('Invalid values for scissor. All values should be positive.'));
803+
}
804+
805+
try {
806+
state.renderPass.setScissor(gpu.Scissor(width: 50, height: -100));
807+
fail('Exception not thrown for invalid scissor.');
808+
} catch (e) {
809+
expect(e.toString(),
810+
contains('Invalid values for scissor. All values should be positive.'));
811+
}
812+
}, skip: !impellerEnabled);
739813
}

0 commit comments

Comments
 (0)