[Flutter GPU] Added support to set Scissor. (flutter/engine#56302)

Added support to set scissors. This resolves issue #157199
This commit is contained in:
AthulJoseph 2024-11-21 11:22:54 +05:30 committed by GitHub
parent 69da421d98
commit 4705535548
4 changed files with 123 additions and 0 deletions

View File

@ -150,6 +150,18 @@ 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;
void _validate() {
if (x < 0 || y < 0 || width < 0 || height < 0) {
throw Exception("Invalid values for scissor. All values should be positive.");
}
}
}
base class RenderTarget {
const RenderTarget(
{this.colorAttachments = const <ColorAttachment>[],
@ -326,6 +338,14 @@ base class RenderPass extends NativeFieldWrapperClass1 {
targetFace.index);
}
void setScissor(Scissor scissor) {
assert(() {
scissor._validate();
return true;
}());
_setScissor(scissor.x, scissor.y, scissor.width, scissor.height);
}
void setCullMode(CullMode cullMode) {
_setCullMode(cullMode.index);
}
@ -478,6 +498,14 @@ base class RenderPass extends NativeFieldWrapperClass1 {
int writeMask,
int target_face);
@Native<Void Function(Pointer<Void>, Int, Int, Int, Int)>(
symbol: 'InternalFlutterGpu_RenderPass_SetScissor')
external void _setScissor(
int x,
int y,
int width,
int height);
@Native<Void Function(Pointer<Void>, Int)>(
symbol: 'InternalFlutterGpu_RenderPass_SetCullMode')
external void _setCullMode(int cullMode);

View File

@ -207,6 +207,10 @@ bool RenderPass::Draw() {
render_pass_->SetStencilReference(stencil_reference);
if (scissor.has_value()) {
render_pass_->SetScissor(scissor.value());
}
bool result = render_pass_->Draw().ok();
return result;
@ -536,6 +540,14 @@ void InternalFlutterGpu_RenderPass_SetStencilReference(
wrapper->stencil_reference = static_cast<uint32_t>(stencil_reference);
}
void InternalFlutterGpu_RenderPass_SetScissor(flutter::gpu::RenderPass* wrapper,
int x,
int y,
int width,
int height) {
wrapper->scissor = impeller::TRect<int64_t>::MakeXYWH(x, y, width, height);
}
void InternalFlutterGpu_RenderPass_SetStencilConfig(
flutter::gpu::RenderPass* wrapper,
int stencil_compare_operation,

View File

@ -74,6 +74,7 @@ class RenderPass : public RefCountedDartWrappable<RenderPass> {
size_t element_count = 0;
uint32_t stencil_reference = 0;
std::optional<impeller::TRect<int64_t>> 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,

View File

@ -736,4 +736,78 @@ 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, width: 50, height: 100));
final gpu.HostBuffer transients = gpu.gpuContext.createHostBuffer();
final gpu.BufferView vertices = transients.emplace(float32(<double>[
-1.0,
-1.0,
0.0,
1.0,
1.0,
-1.0]));
final gpu.BufferView vertInfoData = transients.emplace(float32(<double>[
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);
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);
}