Skip to content

Commit f6b0598

Browse files
Added support to set viewport (#162602)
Resolves #157201.
1 parent c783ce2 commit f6b0598

File tree

4 files changed

+158
-0
lines changed

4 files changed

+158
-0
lines changed

engine/src/flutter/lib/gpu/lib/src/render_pass.dart

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,34 @@ base class Scissor {
168168
}
169169
}
170170

171+
base class DepthRange {
172+
DepthRange({this.zNear = 0.0, this.zFar = 1.0});
173+
174+
double zNear;
175+
double zFar;
176+
}
177+
178+
base class Viewport {
179+
Viewport({
180+
this.x = 0,
181+
this.y = 0,
182+
this.width = 0,
183+
this.height = 0,
184+
DepthRange? depthRange = null,
185+
}) : this.depthRange = depthRange ?? DepthRange();
186+
187+
int x, y, width, height;
188+
DepthRange depthRange;
189+
190+
void _validate() {
191+
if (x < 0 || y < 0 || width < 0 || height < 0) {
192+
throw Exception(
193+
"Invalid values for viewport. All values should be positive.",
194+
);
195+
}
196+
}
197+
}
198+
171199
base class RenderTarget {
172200
const RenderTarget({
173201
this.colorAttachments = const <ColorAttachment>[],
@@ -346,6 +374,21 @@ base class RenderPass extends NativeFieldWrapperClass1 {
346374
_setDepthWriteEnable(enable);
347375
}
348376

377+
void setViewport(Viewport viewport) {
378+
assert(() {
379+
viewport._validate();
380+
return true;
381+
}());
382+
_setViewport(
383+
viewport.x,
384+
viewport.y,
385+
viewport.width,
386+
viewport.height,
387+
viewport.depthRange.zNear,
388+
viewport.depthRange.zFar,
389+
);
390+
}
391+
349392
void setDepthCompareOperation(CompareFunction compareFunction) {
350393
_setDepthCompareOperation(compareFunction.index);
351394
}
@@ -508,6 +551,18 @@ base class RenderPass extends NativeFieldWrapperClass1 {
508551
int lengthInBytes,
509552
);
510553

554+
@Native<Void Function(Pointer<Void>, Int, Int, Int, Int, Float, Float)>(
555+
symbol: 'InternalFlutterGpu_RenderPass_SetViewport',
556+
)
557+
external void _setViewport(
558+
int x,
559+
int y,
560+
int width,
561+
int height,
562+
double depthRangeZNear,
563+
double depthRangeZFar,
564+
);
565+
511566
@Native<
512567
Bool Function(
513568
Pointer<Void>,

engine/src/flutter/lib/gpu/render_pass.cc

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

219219
render_pass_->SetStencilReference(stencil_reference);
220220

221+
if (viewport.has_value()) {
222+
render_pass_->SetViewport(viewport.value());
223+
}
224+
221225
if (scissor.has_value()) {
222226
render_pass_->SetScissor(scissor.value());
223227
}
@@ -559,6 +563,27 @@ void InternalFlutterGpu_RenderPass_SetScissor(flutter::gpu::RenderPass* wrapper,
559563
wrapper->scissor = impeller::TRect<int64_t>::MakeXYWH(x, y, width, height);
560564
}
561565

566+
void InternalFlutterGpu_RenderPass_SetViewport(
567+
flutter::gpu::RenderPass* wrapper,
568+
int x,
569+
int y,
570+
int width,
571+
int height,
572+
float z_near,
573+
float z_far) {
574+
auto rect = impeller::TRect<float>::MakeXYWH(x, y, width, height);
575+
576+
auto depth_range = impeller::DepthRange();
577+
depth_range.z_near = z_near;
578+
depth_range.z_far = z_far;
579+
580+
auto viewport = impeller::Viewport();
581+
viewport.rect = rect;
582+
viewport.depth_range = depth_range;
583+
584+
wrapper->viewport = viewport;
585+
}
586+
562587
void InternalFlutterGpu_RenderPass_SetStencilConfig(
563588
flutter::gpu::RenderPass* wrapper,
564589
int stencil_compare_operation,

engine/src/flutter/lib/gpu/render_pass.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ class RenderPass : public RefCountedDartWrappable<RenderPass> {
8181

8282
uint32_t stencil_reference = 0;
8383
std::optional<impeller::TRect<int64_t>> scissor;
84+
std::optional<impeller::Viewport> viewport;
8485

8586
// Helper flag to determine whether the vertex_count should override the
8687
// element count. The index count takes precedent.
@@ -249,6 +250,16 @@ extern void InternalFlutterGpu_RenderPass_SetScissor(
249250
int width,
250251
int height);
251252

253+
FLUTTER_GPU_EXPORT
254+
extern void InternalFlutterGpu_RenderPass_SetViewport(
255+
flutter::gpu::RenderPass* wrapper,
256+
int x,
257+
int y,
258+
int width,
259+
int height,
260+
float z_near,
261+
float z_far);
262+
252263
FLUTTER_GPU_EXPORT
253264
extern void InternalFlutterGpu_RenderPass_SetCullMode(
254265
flutter::gpu::RenderPass* wrapper,

engine/src/flutter/testing/dart/gpu_test.dart

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,4 +810,71 @@ void main() async {
810810
expect(e.toString(), contains('Invalid values for scissor. All values should be positive.'));
811811
}
812812
}, skip: !impellerEnabled);
813+
814+
test('RenderPass.setViewport doesnt throw for valid values', () async {
815+
final state = createSimpleRenderPass();
816+
817+
state.renderPass.setViewport(gpu.Viewport(x: 25, width: 50, height: 100));
818+
state.renderPass.setViewport(gpu.Viewport(width: 50, height: 100));
819+
}, skip: !impellerEnabled);
820+
821+
test('RenderPass.setViewport throws for invalid values', () async {
822+
final state = createSimpleRenderPass();
823+
824+
try {
825+
state.renderPass.setViewport(gpu.Viewport(x: -1, width: 50, height: 100));
826+
fail('Exception not thrown for invalid viewport.');
827+
} catch (e) {
828+
expect(e.toString(), contains('Invalid values for viewport. All values should be positive.'));
829+
}
830+
831+
try {
832+
state.renderPass.setViewport(gpu.Viewport(width: 50, height: -100));
833+
fail('Exception not thrown for invalid viewport.');
834+
} catch (e) {
835+
expect(e.toString(), contains('Invalid values for viewport. All values should be positive.'));
836+
}
837+
}, skip: !impellerEnabled);
838+
839+
// Renders the middle part triangle using viewport.
840+
test('Can render portion of the triangle using viewport', () async {
841+
final state = createSimpleRenderPass();
842+
843+
final gpu.RenderPipeline pipeline = createUnlitRenderPipeline();
844+
state.renderPass.bindPipeline(pipeline);
845+
846+
// Configure blending with defaults (just to test the bindings).
847+
state.renderPass.setColorBlendEnable(true);
848+
state.renderPass.setColorBlendEquation(gpu.ColorBlendEquation());
849+
850+
// Set primitive type.
851+
state.renderPass.setPrimitiveType(gpu.PrimitiveType.triangle);
852+
853+
// Set viewport.
854+
state.renderPass.setViewport(gpu.Viewport(x: 25, width: 50, height: 100));
855+
856+
final gpu.HostBuffer transients = gpu.gpuContext.createHostBuffer();
857+
final gpu.BufferView vertices = transients.emplace(
858+
float32(<double>[-1.0, -1.0, 0.0, 1.0, 1.0, -1.0]),
859+
);
860+
final gpu.BufferView vertInfoData = transients.emplace(
861+
float32(<double>[
862+
1, 0, 0, 0, // mvp
863+
0, 1, 0, 0, // mvp
864+
0, 0, 1, 0, // mvp
865+
0, 0, 0, 1, // mvp
866+
0, 1, 0, 1, // color
867+
]),
868+
);
869+
state.renderPass.bindVertexBuffer(vertices, 3);
870+
871+
final gpu.UniformSlot vertInfo = pipeline.vertexShader.getUniformSlot('VertInfo');
872+
state.renderPass.bindUniform(vertInfo, vertInfoData);
873+
state.renderPass.draw();
874+
875+
state.commandBuffer.submit();
876+
877+
final ui.Image image = state.renderTexture.asImage();
878+
await comparer.addGoldenImage(image, 'flutter_gpu_test_viewport.png');
879+
}, skip: !impellerEnabled);
813880
}

0 commit comments

Comments
 (0)