Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/servers/rendering/renderer_viewport.cpp
21097 views
1
/**************************************************************************/
2
/* renderer_viewport.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "renderer_viewport.h"
32
33
#include "core/config/project_settings.h"
34
#include "core/math/transform_interpolator.h"
35
#include "core/object/worker_thread_pool.h"
36
#include "core/profiling/profiling.h"
37
#include "renderer_canvas_cull.h"
38
#include "renderer_scene_cull.h"
39
#include "rendering_server_globals.h"
40
#include "storage/texture_storage.h"
41
42
#ifndef XR_DISABLED
43
#include "servers/xr/xr_interface.h"
44
#endif // XR_DISABLED
45
46
static Transform2D _canvas_get_transform(RendererViewport::Viewport *p_viewport, RendererCanvasCull::Canvas *p_canvas, RendererViewport::Viewport::CanvasData *p_canvas_data, const Vector2 &p_vp_size) {
47
Transform2D xf = p_viewport->global_transform;
48
49
Vector2 pixel_snap_offset;
50
if (p_viewport->snap_2d_transforms_to_pixel) {
51
// We use `floor(p + 0.5)` to snap canvas items, but `ceil(p - 0.5)`
52
// to snap viewport transform because the viewport transform is inverse
53
// to the camera transform. Also, if the viewport size is not divisible
54
// by 2, the center point is offset by 0.5 px and we need to add 0.5
55
// before rounding to cancel it out.
56
pixel_snap_offset.x = (p_viewport->size.width % 2) ? 0.0 : -0.5;
57
pixel_snap_offset.y = (p_viewport->size.height % 2) ? 0.0 : -0.5;
58
}
59
60
float scale = 1.0;
61
if (p_viewport->canvas_map.has(p_canvas->parent)) {
62
Transform2D c_xform = p_viewport->canvas_map[p_canvas->parent].transform;
63
if (p_viewport->snap_2d_transforms_to_pixel) {
64
c_xform.columns[2] = (c_xform.columns[2] * p_canvas->parent_scale + pixel_snap_offset).ceil() / p_canvas->parent_scale;
65
}
66
xf = xf * c_xform;
67
scale = p_canvas->parent_scale;
68
}
69
70
Transform2D c_xform = p_canvas_data->transform;
71
if (p_viewport->snap_2d_transforms_to_pixel) {
72
c_xform.columns[2] = (c_xform.columns[2] + pixel_snap_offset).ceil();
73
}
74
xf = xf * c_xform;
75
76
if (scale != 1.0 && !RSG::canvas->disable_scale) {
77
Vector2 pivot = p_vp_size * 0.5;
78
Transform2D xfpivot;
79
xfpivot.set_origin(pivot);
80
Transform2D xfscale;
81
xfscale.scale(Vector2(scale, scale));
82
83
xf = xfpivot.affine_inverse() * xf;
84
xf = xfscale * xf;
85
xf = xfpivot * xf;
86
}
87
88
return xf;
89
}
90
91
Vector<RendererViewport::Viewport *> RendererViewport::_sort_active_viewports() {
92
// We need to sort the viewports in a "topological order", children first and
93
// parents last. We also need to keep sibling viewports in the original order
94
// from top to bottom.
95
96
Vector<Viewport *> result;
97
List<Viewport *> nodes;
98
99
for (int i = active_viewports.size() - 1; i >= 0; --i) {
100
Viewport *viewport = active_viewports[i];
101
if (viewport->parent.is_valid()) {
102
continue;
103
}
104
105
nodes.push_back(viewport);
106
result.insert(0, viewport);
107
}
108
109
while (!nodes.is_empty()) {
110
const Viewport *node = nodes.front()->get();
111
nodes.pop_front();
112
113
for (int i = active_viewports.size() - 1; i >= 0; --i) {
114
Viewport *child = active_viewports[i];
115
if (child->parent != node->self) {
116
continue;
117
}
118
119
if (!nodes.find(child)) {
120
nodes.push_back(child);
121
result.insert(0, child);
122
}
123
}
124
}
125
126
return result;
127
}
128
129
void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) {
130
if (p_viewport->render_buffers.is_valid()) {
131
if (p_viewport->size.width == 0 || p_viewport->size.height == 0) {
132
p_viewport->render_buffers.unref();
133
} else {
134
const float EPSILON = 0.0001;
135
float scaling_3d_scale = p_viewport->scaling_3d_scale;
136
RS::ViewportScaling3DMode scaling_3d_mode = p_viewport->scaling_3d_mode;
137
bool upscaler_available = p_viewport->fsr_enabled;
138
RS::ViewportScaling3DType scaling_type = RS::scaling_3d_mode_type(scaling_3d_mode);
139
140
if ((!upscaler_available || (scaling_type == RS::VIEWPORT_SCALING_3D_TYPE_SPATIAL)) && scaling_3d_scale >= (1.0 - EPSILON) && scaling_3d_scale <= (1.0 + EPSILON)) {
141
// No 3D scaling for spatial modes? Ignore scaling mode, this just introduces overhead.
142
// - Mobile can't perform optimal path
143
// - FSR does an extra pass (or 2 extra passes if 2D-MSAA is enabled)
144
// Scaling = 1.0 on FSR2 and MetalFX temporal has benefits
145
scaling_3d_scale = 1.0;
146
scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_OFF;
147
}
148
149
if (scaling_3d_mode != RS::VIEWPORT_SCALING_3D_MODE_OFF && scaling_3d_mode != RS::VIEWPORT_SCALING_3D_MODE_BILINEAR && OS::get_singleton()->get_current_rendering_method() == "gl_compatibility") {
150
scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_BILINEAR;
151
scaling_type = RS::scaling_3d_mode_type(scaling_3d_mode);
152
WARN_PRINT_ONCE("MetalFX and FSR upscaling are not supported in the Compatibility renderer. Falling back to bilinear scaling.");
153
}
154
155
if (scaling_3d_mode == RS::VIEWPORT_SCALING_3D_MODE_METALFX_TEMPORAL && !RD::get_singleton()->has_feature(RD::SUPPORTS_METALFX_TEMPORAL)) {
156
if (RD::get_singleton()->has_feature(RD::SUPPORTS_METALFX_SPATIAL)) {
157
// Prefer MetalFX spatial if it is supported, which will be much more efficient than FSR2,
158
// as the hardware already will struggle with FSR2.
159
scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_METALFX_SPATIAL;
160
WARN_PRINT_ONCE("MetalFX temporal upscaling is not supported by the current renderer or hardware. Falling back to MetalFX Spatial scaling.");
161
} else {
162
scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_FSR2;
163
WARN_PRINT_ONCE("MetalFX upscaling is not supported by the current renderer or hardware. Falling back to FSR 2 scaling.");
164
}
165
scaling_type = RS::scaling_3d_mode_type(scaling_3d_mode);
166
}
167
168
if (scaling_3d_mode == RS::VIEWPORT_SCALING_3D_MODE_METALFX_SPATIAL && !RD::get_singleton()->has_feature(RD::SUPPORTS_METALFX_SPATIAL)) {
169
scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_FSR;
170
WARN_PRINT_ONCE("MetalFX spatial upscaling is not supported by the current renderer or hardware. Falling back to FSR scaling.");
171
}
172
173
RS::ViewportMSAA msaa_3d = p_viewport->msaa_3d;
174
175
// If MetalFX Temporal upscaling is supported, verify limits.
176
if (scaling_3d_mode == RS::VIEWPORT_SCALING_3D_MODE_METALFX_TEMPORAL) {
177
double min_scale = (double)RD::get_singleton()->limit_get(RD::LIMIT_METALFX_TEMPORAL_SCALER_MIN_SCALE) / 1000'000.0;
178
double max_scale = (double)RD::get_singleton()->limit_get(RD::LIMIT_METALFX_TEMPORAL_SCALER_MAX_SCALE) / 1000'000.0;
179
if ((double)scaling_3d_scale < min_scale || (double)scaling_3d_scale > max_scale) {
180
scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_FSR2;
181
WARN_PRINT_ONCE(vformat("MetalFX temporal upscaling scale is outside limits; scale must be between %f and %f. Falling back to FSR 2 3D resolution scaling.", min_scale, max_scale));
182
} else if (msaa_3d != RS::VIEWPORT_MSAA_DISABLED) {
183
WARN_PRINT_ONCE("MetalFX temporal upscaling does not support 3D MSAA. Disabling 3D MSAA internally.");
184
msaa_3d = RS::VIEWPORT_MSAA_DISABLED;
185
}
186
}
187
188
bool scaling_3d_is_not_bilinear = scaling_3d_mode != RS::VIEWPORT_SCALING_3D_MODE_OFF && scaling_3d_mode != RS::VIEWPORT_SCALING_3D_MODE_BILINEAR;
189
bool use_taa = p_viewport->use_taa;
190
191
if (scaling_3d_is_not_bilinear && (scaling_3d_scale >= (1.0 + EPSILON))) {
192
// FSR and MetalFX is not designed for downsampling.
193
// Fall back to bilinear scaling.
194
WARN_PRINT_ONCE("FSR 3D resolution scaling is not designed for downsampling. Falling back to bilinear 3D resolution scaling.");
195
scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_BILINEAR;
196
scaling_type = RS::scaling_3d_mode_type(scaling_3d_mode);
197
}
198
199
if (scaling_3d_is_not_bilinear && !upscaler_available) {
200
// FSR is not actually available.
201
// Fall back to bilinear scaling.
202
WARN_PRINT_ONCE("FSR 3D resolution scaling is not available. Falling back to bilinear 3D resolution scaling.");
203
scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_BILINEAR;
204
scaling_type = RS::scaling_3d_mode_type(scaling_3d_mode);
205
}
206
207
if (use_taa && (scaling_type == RS::VIEWPORT_SCALING_3D_TYPE_TEMPORAL)) {
208
// Temporal upscalers can't be used with TAA.
209
// Turn it off and prefer using the temporal upscaler.
210
WARN_PRINT_ONCE("FSR 2 or MetalFX Temporal is not compatible with TAA. Disabling TAA internally.");
211
use_taa = false;
212
}
213
214
int target_width;
215
int target_height;
216
int render_width;
217
int render_height;
218
219
switch (scaling_3d_mode) {
220
case RS::VIEWPORT_SCALING_3D_MODE_BILINEAR:
221
// Clamp 3D rendering resolution to reasonable values supported on most hardware.
222
// This prevents freezing the engine or outright crashing on lower-end GPUs.
223
target_width = p_viewport->size.width;
224
target_height = p_viewport->size.height;
225
render_width = CLAMP(target_width * scaling_3d_scale, 1, 16384);
226
render_height = CLAMP(target_height * scaling_3d_scale, 1, 16384);
227
break;
228
case RS::VIEWPORT_SCALING_3D_MODE_METALFX_SPATIAL:
229
case RS::VIEWPORT_SCALING_3D_MODE_METALFX_TEMPORAL:
230
case RS::VIEWPORT_SCALING_3D_MODE_FSR:
231
case RS::VIEWPORT_SCALING_3D_MODE_FSR2:
232
target_width = p_viewport->size.width;
233
target_height = p_viewport->size.height;
234
render_width = MAX(target_width * scaling_3d_scale, 1.0); // target_width / (target_width * scaling)
235
render_height = MAX(target_height * scaling_3d_scale, 1.0);
236
break;
237
case RS::VIEWPORT_SCALING_3D_MODE_OFF:
238
target_width = p_viewport->size.width;
239
target_height = p_viewport->size.height;
240
render_width = target_width;
241
render_height = target_height;
242
break;
243
default:
244
// This is an unknown mode.
245
WARN_PRINT_ONCE(vformat("Unknown scaling mode: %d. Disabling 3D resolution scaling.", scaling_3d_mode));
246
scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_OFF;
247
scaling_3d_scale = 1.0;
248
target_width = p_viewport->size.width;
249
target_height = p_viewport->size.height;
250
render_width = target_width;
251
render_height = target_height;
252
break;
253
}
254
255
uint32_t jitter_phase_count = 0;
256
if (scaling_type == RS::VIEWPORT_SCALING_3D_TYPE_TEMPORAL) {
257
// Implementation has been copied from ffxFsr2GetJitterPhaseCount.
258
// Also used for MetalFX Temporal scaling.
259
jitter_phase_count = uint32_t(8.0f * std::pow(float(target_width) / render_width, 2.0f));
260
} else if (use_taa) {
261
// Default jitter count for TAA.
262
jitter_phase_count = 16;
263
}
264
265
p_viewport->internal_size = Size2(render_width, render_height);
266
p_viewport->jitter_phase_count = jitter_phase_count;
267
268
// At resolution scales lower than 1.0, use negative texture mipmap bias
269
// to compensate for the loss of sharpness.
270
const float texture_mipmap_bias = std::log2(MIN(scaling_3d_scale, 1.0)) + p_viewport->texture_mipmap_bias;
271
272
RenderSceneBuffersConfiguration rb_config;
273
rb_config.set_render_target(p_viewport->render_target);
274
rb_config.set_internal_size(Size2i(render_width, render_height));
275
rb_config.set_target_size(Size2(target_width, target_height));
276
rb_config.set_view_count(p_viewport->view_count);
277
rb_config.set_scaling_3d_mode(scaling_3d_mode);
278
rb_config.set_msaa_3d(msaa_3d);
279
rb_config.set_screen_space_aa(p_viewport->screen_space_aa);
280
rb_config.set_fsr_sharpness(p_viewport->fsr_sharpness);
281
rb_config.set_texture_mipmap_bias(texture_mipmap_bias);
282
rb_config.set_anisotropic_filtering_level(p_viewport->anisotropic_filtering_level);
283
rb_config.set_use_taa(use_taa);
284
rb_config.set_use_debanding(p_viewport->use_debanding);
285
286
p_viewport->render_buffers->configure(&rb_config);
287
}
288
}
289
}
290
291
void RendererViewport::_draw_3d(Viewport *p_viewport) {
292
#ifndef _3D_DISABLED
293
RENDER_TIMESTAMP("> Render 3D Scene");
294
295
Ref<XRInterface> xr_interface;
296
#ifndef XR_DISABLED
297
if (p_viewport->use_xr && XRServer::get_singleton() != nullptr) {
298
xr_interface = XRServer::get_singleton()->get_primary_interface();
299
}
300
#endif // XR_DISABLED
301
302
if (p_viewport->use_occlusion_culling) {
303
if (p_viewport->occlusion_buffer_dirty) {
304
float aspect = p_viewport->size.aspect();
305
int max_size = occlusion_rays_per_thread * WorkerThreadPool::get_singleton()->get_thread_count();
306
307
int viewport_size = p_viewport->size.width * p_viewport->size.height;
308
max_size = CLAMP(max_size, viewport_size / (32 * 32), viewport_size / (2 * 2)); // At least one depth pixel for every 16x16 region. At most one depth pixel for every 2x2 region.
309
310
float height = Math::sqrt(max_size / aspect);
311
Size2i new_size = Size2i(height * aspect, height);
312
RendererSceneOcclusionCull::get_singleton()->buffer_set_size(p_viewport->self, new_size);
313
p_viewport->occlusion_buffer_dirty = false;
314
}
315
}
316
317
float screen_mesh_lod_threshold = p_viewport->mesh_lod_threshold / float(p_viewport->size.width);
318
RSG::scene->render_camera(p_viewport->render_buffers, p_viewport->camera, p_viewport->scenario, p_viewport->self, p_viewport->internal_size, p_viewport->jitter_phase_count, screen_mesh_lod_threshold, p_viewport->shadow_atlas, xr_interface, &p_viewport->render_info);
319
320
RENDER_TIMESTAMP("< Render 3D Scene");
321
#endif // _3D_DISABLED
322
}
323
324
void RendererViewport::_draw_viewport(Viewport *p_viewport) {
325
if (p_viewport->measure_render_time) {
326
String rt_id = "vp_begin_" + itos(p_viewport->self.get_id());
327
RSG::utilities->capture_timestamp(rt_id);
328
timestamp_vp_map[rt_id] = p_viewport->self;
329
}
330
331
if (OS::get_singleton()->get_current_rendering_method() == "gl_compatibility") {
332
// This is currently needed for GLES to keep the current window being rendered to up to date
333
DisplayServer::get_singleton()->gl_window_make_current(p_viewport->viewport_to_screen);
334
}
335
336
/* Camera should always be BEFORE any other 3D */
337
338
bool can_draw_2d = !p_viewport->disable_2d && p_viewport->view_count == 1; // Stereo rendering does not support 2D, no depth data
339
bool scenario_draw_canvas_bg = false; //draw canvas, or some layer of it, as BG for 3D instead of in front
340
int scenario_canvas_max_layer = 0;
341
bool force_clear_render_target = false;
342
343
for (int i = 0; i < RS::VIEWPORT_RENDER_INFO_TYPE_MAX; i++) {
344
for (int j = 0; j < RS::VIEWPORT_RENDER_INFO_MAX; j++) {
345
p_viewport->render_info.info[i][j] = 0;
346
}
347
}
348
349
if (RSG::scene->is_scenario(p_viewport->scenario)) {
350
RID environment = RSG::scene->scenario_get_environment(p_viewport->scenario);
351
if (RSG::scene->is_environment(environment)) {
352
if (can_draw_2d && !viewport_is_environment_disabled(p_viewport)) {
353
scenario_draw_canvas_bg = RSG::scene->environment_get_background(environment) == RS::ENV_BG_CANVAS;
354
scenario_canvas_max_layer = RSG::scene->environment_get_canvas_max_layer(environment);
355
} else if (RSG::scene->environment_get_background(environment) == RS::ENV_BG_CANVAS) {
356
// The scene renderer will still copy over the last frame, so we need to clear the render target.
357
force_clear_render_target = true;
358
}
359
}
360
}
361
362
bool can_draw_3d = RSG::scene->is_camera(p_viewport->camera) && !p_viewport->disable_3d;
363
364
if ((scenario_draw_canvas_bg || can_draw_3d) && !p_viewport->render_buffers.is_valid()) {
365
//wants to draw 3D but there is no render buffer, create
366
p_viewport->render_buffers = RSG::scene->render_buffers_create();
367
368
_configure_3d_render_buffers(p_viewport);
369
}
370
371
Color bgcolor = p_viewport->transparent_bg ? Color(0, 0, 0, 0) : RSG::texture_storage->get_default_clear_color();
372
373
if (p_viewport->clear_mode != RS::VIEWPORT_CLEAR_NEVER) {
374
RSG::texture_storage->render_target_request_clear(p_viewport->render_target, bgcolor);
375
if (p_viewport->clear_mode == RS::VIEWPORT_CLEAR_ONLY_NEXT_FRAME) {
376
p_viewport->clear_mode = RS::VIEWPORT_CLEAR_NEVER;
377
}
378
}
379
380
if (!scenario_draw_canvas_bg && can_draw_3d) {
381
if (force_clear_render_target) {
382
RSG::texture_storage->render_target_do_clear_request(p_viewport->render_target);
383
}
384
_draw_3d(p_viewport);
385
}
386
387
if (can_draw_2d) {
388
RBMap<Viewport::CanvasKey, Viewport::CanvasData *> canvas_map;
389
390
Rect2 clip_rect(0, 0, p_viewport->size.x, p_viewport->size.y);
391
RendererCanvasRender::Light *lights = nullptr;
392
RendererCanvasRender::Light *lights_with_shadow = nullptr;
393
394
RendererCanvasRender::Light *directional_lights = nullptr;
395
RendererCanvasRender::Light *directional_lights_with_shadow = nullptr;
396
397
if (p_viewport->sdf_active) {
398
// Process SDF.
399
400
Rect2 sdf_rect = RSG::texture_storage->render_target_get_sdf_rect(p_viewport->render_target);
401
402
RendererCanvasRender::LightOccluderInstance *occluders = nullptr;
403
404
// Make list of occluders.
405
for (KeyValue<RID, Viewport::CanvasData> &E : p_viewport->canvas_map) {
406
RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E.value.canvas);
407
Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E.value, clip_rect.size);
408
409
for (RendererCanvasRender::LightOccluderInstance *F : canvas->occluders) {
410
if (!F->enabled) {
411
continue;
412
}
413
414
if (!RSG::canvas->_interpolation_data.interpolation_enabled || !F->interpolated) {
415
F->xform_cache = xf * F->xform_curr;
416
} else {
417
real_t f = Engine::get_singleton()->get_physics_interpolation_fraction();
418
TransformInterpolator::interpolate_transform_2d(F->xform_prev, F->xform_curr, F->xform_cache, f);
419
F->xform_cache = xf * F->xform_cache;
420
}
421
422
if (sdf_rect.intersects_transformed(F->xform_cache, F->aabb_cache)) {
423
F->next = occluders;
424
occluders = F;
425
}
426
}
427
}
428
429
RSG::canvas_render->render_sdf(p_viewport->render_target, occluders);
430
RSG::texture_storage->render_target_mark_sdf_enabled(p_viewport->render_target, true);
431
432
p_viewport->sdf_active = false; // If used, gets set active again.
433
} else {
434
RSG::texture_storage->render_target_mark_sdf_enabled(p_viewport->render_target, false);
435
}
436
437
Rect2 shadow_rect;
438
439
int shadow_count = 0;
440
int directional_light_count = 0;
441
442
RENDER_TIMESTAMP("Cull 2D Lights");
443
for (KeyValue<RID, Viewport::CanvasData> &E : p_viewport->canvas_map) {
444
RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E.value.canvas);
445
446
Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E.value, clip_rect.size);
447
448
// Find lights in canvas.
449
450
for (RendererCanvasRender::Light *F : canvas->lights) {
451
RendererCanvasRender::Light *cl = F;
452
if (cl->enabled && cl->texture.is_valid()) {
453
//not super efficient..
454
Size2 tsize = RSG::texture_storage->texture_size_with_proxy(cl->texture);
455
tsize *= cl->scale;
456
457
Vector2 offset = tsize / 2.0;
458
Rect2 local_rect = Rect2(-offset + cl->texture_offset, tsize);
459
460
if (!RSG::canvas->_interpolation_data.interpolation_enabled || !cl->interpolated) {
461
cl->xform_cache = xf * cl->xform_curr;
462
} else {
463
real_t f = Engine::get_singleton()->get_physics_interpolation_fraction();
464
TransformInterpolator::interpolate_transform_2d(cl->xform_prev, cl->xform_curr, cl->xform_cache, f);
465
cl->xform_cache = xf * cl->xform_cache;
466
}
467
468
cl->rect_cache = cl->xform_cache.xform(local_rect);
469
470
if (clip_rect.intersects(cl->rect_cache)) {
471
cl->filter_next_ptr = lights;
472
lights = cl;
473
Transform2D scale;
474
scale.scale(local_rect.size);
475
scale.columns[2] = local_rect.position;
476
cl->light_shader_xform = cl->xform_cache * scale;
477
if (cl->use_shadow) {
478
cl->shadows_next_ptr = lights_with_shadow;
479
if (lights_with_shadow == nullptr) {
480
shadow_rect = cl->rect_cache;
481
} else {
482
shadow_rect = shadow_rect.merge(cl->rect_cache);
483
}
484
lights_with_shadow = cl;
485
cl->radius_cache = local_rect.size.length();
486
}
487
}
488
}
489
}
490
491
for (RendererCanvasRender::Light *F : canvas->directional_lights) {
492
RendererCanvasRender::Light *cl = F;
493
if (cl->enabled) {
494
cl->filter_next_ptr = directional_lights;
495
directional_lights = cl;
496
if (!RSG::canvas->_interpolation_data.interpolation_enabled || !cl->interpolated) {
497
cl->xform_cache = xf * cl->xform_curr;
498
} else {
499
real_t f = Engine::get_singleton()->get_physics_interpolation_fraction();
500
TransformInterpolator::interpolate_transform_2d(cl->xform_prev, cl->xform_curr, cl->xform_cache, f);
501
cl->xform_cache = xf * cl->xform_cache;
502
}
503
cl->xform_cache.columns[2] = Vector2(); //translation is pointless
504
if (cl->use_shadow) {
505
cl->shadows_next_ptr = directional_lights_with_shadow;
506
directional_lights_with_shadow = cl;
507
}
508
509
directional_light_count++;
510
511
if (directional_light_count == RS::MAX_2D_DIRECTIONAL_LIGHTS) {
512
break;
513
}
514
}
515
}
516
517
canvas_map[Viewport::CanvasKey(E.key, E.value.layer, E.value.sublayer)] = &E.value;
518
}
519
520
if (lights_with_shadow) {
521
//update shadows if any
522
523
RendererCanvasRender::LightOccluderInstance *occluders = nullptr;
524
525
RENDER_TIMESTAMP("> Render PointLight2D Shadows");
526
RENDER_TIMESTAMP("Cull LightOccluder2Ds");
527
528
//make list of occluders
529
for (KeyValue<RID, Viewport::CanvasData> &E : p_viewport->canvas_map) {
530
RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E.value.canvas);
531
Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E.value, clip_rect.size);
532
533
for (RendererCanvasRender::LightOccluderInstance *F : canvas->occluders) {
534
if (!F->enabled) {
535
continue;
536
}
537
if (!RSG::canvas->_interpolation_data.interpolation_enabled || !F->interpolated) {
538
F->xform_cache = xf * F->xform_curr;
539
} else {
540
real_t f = Engine::get_singleton()->get_physics_interpolation_fraction();
541
TransformInterpolator::interpolate_transform_2d(F->xform_prev, F->xform_curr, F->xform_cache, f);
542
F->xform_cache = xf * F->xform_cache;
543
}
544
if (shadow_rect.intersects_transformed(F->xform_cache, F->aabb_cache)) {
545
F->next = occluders;
546
occluders = F;
547
}
548
}
549
}
550
//update the light shadowmaps with them
551
552
RendererCanvasRender::Light *light = lights_with_shadow;
553
while (light) {
554
RENDER_TIMESTAMP("Render PointLight2D Shadow");
555
556
RSG::canvas_render->light_update_shadow(light->light_internal, shadow_count++, light->xform_cache.affine_inverse(), light->item_shadow_mask, light->radius_cache / 1000.0, light->radius_cache * 1.1, occluders, light->rect_cache);
557
light = light->shadows_next_ptr;
558
}
559
560
RENDER_TIMESTAMP("< Render PointLight2D Shadows");
561
}
562
563
if (directional_lights_with_shadow) {
564
//update shadows if any
565
RendererCanvasRender::Light *light = directional_lights_with_shadow;
566
while (light) {
567
Vector2 light_dir = -light->xform_cache.columns[1].normalized(); // Y is light direction
568
float cull_distance = light->directional_distance;
569
570
Vector2 light_dir_sign;
571
light_dir_sign.x = (Math::abs(light_dir.x) < CMP_EPSILON) ? 0.0 : ((light_dir.x > 0.0) ? 1.0 : -1.0);
572
light_dir_sign.y = (Math::abs(light_dir.y) < CMP_EPSILON) ? 0.0 : ((light_dir.y > 0.0) ? 1.0 : -1.0);
573
574
Vector2 points[6];
575
int point_count = 0;
576
577
for (int j = 0; j < 4; j++) {
578
static const Vector2 signs[4] = { Vector2(1, 1), Vector2(1, 0), Vector2(0, 0), Vector2(0, 1) };
579
Vector2 sign_cmp = signs[j] * 2.0 - Vector2(1.0, 1.0);
580
Vector2 point = clip_rect.position + clip_rect.size * signs[j];
581
582
if (sign_cmp == light_dir_sign) {
583
//both point in same direction, plot offsetted
584
points[point_count++] = point + light_dir * cull_distance;
585
} else if (sign_cmp.x == light_dir_sign.x || sign_cmp.y == light_dir_sign.y) {
586
int next_j = (j + 1) % 4;
587
Vector2 next_sign_cmp = signs[next_j] * 2.0 - Vector2(1.0, 1.0);
588
589
//one point in the same direction, plot segment
590
591
if (next_sign_cmp.x == light_dir_sign.x || next_sign_cmp.y == light_dir_sign.y) {
592
if (light_dir_sign.x != 0.0 || light_dir_sign.y != 0.0) {
593
points[point_count++] = point;
594
}
595
points[point_count++] = point + light_dir * cull_distance;
596
} else {
597
points[point_count++] = point + light_dir * cull_distance;
598
if (light_dir_sign.x != 0.0 || light_dir_sign.y != 0.0) {
599
points[point_count++] = point;
600
}
601
}
602
} else {
603
//plot normally
604
points[point_count++] = point;
605
}
606
}
607
608
Vector2 xf_points[6];
609
610
RendererCanvasRender::LightOccluderInstance *occluders = nullptr;
611
612
RENDER_TIMESTAMP("> Render DirectionalLight2D Shadows");
613
614
// Make list of occluders.
615
for (KeyValue<RID, Viewport::CanvasData> &E : p_viewport->canvas_map) {
616
RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E.value.canvas);
617
Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E.value, clip_rect.size);
618
619
for (RendererCanvasRender::LightOccluderInstance *F : canvas->occluders) {
620
if (!F->enabled) {
621
continue;
622
}
623
if (!RSG::canvas->_interpolation_data.interpolation_enabled || !F->interpolated) {
624
F->xform_cache = xf * F->xform_curr;
625
} else {
626
real_t f = Engine::get_singleton()->get_physics_interpolation_fraction();
627
TransformInterpolator::interpolate_transform_2d(F->xform_prev, F->xform_curr, F->xform_cache, f);
628
F->xform_cache = xf * F->xform_cache;
629
}
630
Transform2D localizer = F->xform_cache.affine_inverse();
631
632
for (int j = 0; j < point_count; j++) {
633
xf_points[j] = localizer.xform(points[j]);
634
}
635
if (F->aabb_cache.intersects_filled_polygon(xf_points, point_count)) {
636
F->next = occluders;
637
occluders = F;
638
}
639
}
640
}
641
642
RSG::canvas_render->light_update_directional_shadow(light->light_internal, shadow_count++, light->xform_cache, light->item_shadow_mask, cull_distance, clip_rect, occluders);
643
644
light = light->shadows_next_ptr;
645
}
646
647
RENDER_TIMESTAMP("< Render DirectionalLight2D Shadows");
648
}
649
650
if (scenario_draw_canvas_bg && canvas_map.begin() && canvas_map.begin()->key.get_layer() > scenario_canvas_max_layer) {
651
// There may be an outstanding clear request if a clear was requested, but no 2D elements were drawn.
652
// Clear now otherwise we copy over garbage from the render target.
653
RSG::texture_storage->render_target_do_clear_request(p_viewport->render_target);
654
if (!can_draw_3d) {
655
RSG::scene->render_empty_scene(p_viewport->render_buffers, p_viewport->scenario, p_viewport->shadow_atlas);
656
} else {
657
_draw_3d(p_viewport);
658
}
659
scenario_draw_canvas_bg = false;
660
}
661
662
for (const KeyValue<Viewport::CanvasKey, Viewport::CanvasData *> &E : canvas_map) {
663
RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E.value->canvas);
664
665
Transform2D xform = _canvas_get_transform(p_viewport, canvas, E.value, clip_rect.size);
666
667
RendererCanvasRender::Light *canvas_lights = nullptr;
668
RendererCanvasRender::Light *canvas_directional_lights = nullptr;
669
670
RendererCanvasRender::Light *ptr = lights;
671
while (ptr) {
672
if (E.value->layer >= ptr->layer_min && E.value->layer <= ptr->layer_max) {
673
ptr->next_ptr = canvas_lights;
674
canvas_lights = ptr;
675
}
676
ptr = ptr->filter_next_ptr;
677
}
678
679
ptr = directional_lights;
680
while (ptr) {
681
if (E.value->layer >= ptr->layer_min && E.value->layer <= ptr->layer_max) {
682
ptr->next_ptr = canvas_directional_lights;
683
canvas_directional_lights = ptr;
684
}
685
ptr = ptr->filter_next_ptr;
686
}
687
688
RSG::canvas->render_canvas(p_viewport->render_target, canvas, xform, canvas_lights, canvas_directional_lights, clip_rect, p_viewport->texture_filter, p_viewport->texture_repeat, p_viewport->snap_2d_transforms_to_pixel, p_viewport->snap_2d_vertices_to_pixel, p_viewport->canvas_cull_mask, &p_viewport->render_info);
689
if (RSG::canvas->was_sdf_used()) {
690
p_viewport->sdf_active = true;
691
}
692
693
if (scenario_draw_canvas_bg && E.key.get_layer() >= scenario_canvas_max_layer) {
694
// There may be an outstanding clear request if a clear was requested, but no 2D elements were drawn.
695
// Clear now otherwise we copy over garbage from the render target.
696
RSG::texture_storage->render_target_do_clear_request(p_viewport->render_target);
697
if (!can_draw_3d) {
698
RSG::scene->render_empty_scene(p_viewport->render_buffers, p_viewport->scenario, p_viewport->shadow_atlas);
699
} else {
700
_draw_3d(p_viewport);
701
}
702
703
scenario_draw_canvas_bg = false;
704
}
705
}
706
707
if (scenario_draw_canvas_bg) {
708
// There may be an outstanding clear request if a clear was requested, but no 2D elements were drawn.
709
// Clear now otherwise we copy over garbage from the render target.
710
RSG::texture_storage->render_target_do_clear_request(p_viewport->render_target);
711
if (!can_draw_3d) {
712
RSG::scene->render_empty_scene(p_viewport->render_buffers, p_viewport->scenario, p_viewport->shadow_atlas);
713
} else {
714
_draw_3d(p_viewport);
715
}
716
}
717
}
718
719
if (RSG::texture_storage->render_target_is_clear_requested(p_viewport->render_target)) {
720
//was never cleared in the end, force clear it
721
RSG::texture_storage->render_target_do_clear_request(p_viewport->render_target);
722
}
723
724
if (RSG::texture_storage->render_target_get_msaa_needs_resolve(p_viewport->render_target)) {
725
WARN_PRINT_ONCE("2D MSAA is enabled while there is no 2D content. Disable 2D MSAA for better performance.");
726
RSG::texture_storage->render_target_do_msaa_resolve(p_viewport->render_target);
727
}
728
729
if (p_viewport->measure_render_time) {
730
String rt_id = "vp_end_" + itos(p_viewport->self.get_id());
731
RSG::utilities->capture_timestamp(rt_id);
732
timestamp_vp_map[rt_id] = p_viewport->self;
733
}
734
}
735
736
void RendererViewport::draw_viewports(bool p_swap_buffers) {
737
GodotProfileZoneGroupedFirst(_profile_zone, "prepare viewports");
738
timestamp_vp_map.clear();
739
740
#ifndef XR_DISABLED
741
// get our xr interface in case we need it
742
Ref<XRInterface> xr_interface;
743
XRServer *xr_server = XRServer::get_singleton();
744
if (xr_server != nullptr) {
745
// retrieve the interface responsible for rendering
746
xr_interface = xr_server->get_primary_interface();
747
}
748
#endif // XR_DISABLED
749
750
if (Engine::get_singleton()->is_editor_hint()) {
751
RSG::texture_storage->set_default_clear_color(GLOBAL_GET_CACHED(Color, "rendering/environment/defaults/default_clear_color"));
752
}
753
754
if (sorted_active_viewports_dirty) {
755
GodotProfileZoneGrouped(_profile_zone, "_sort_active_viewports");
756
sorted_active_viewports = _sort_active_viewports();
757
sorted_active_viewports_dirty = false;
758
}
759
760
HashMap<DisplayServer::WindowID, Vector<BlitToScreen>> blit_to_screen_list;
761
//draw viewports
762
RENDER_TIMESTAMP("> Render Viewports");
763
764
GodotProfileZoneGrouped(_profile_zone, "render viewports");
765
766
//determine what is visible
767
draw_viewports_pass++;
768
769
for (int i = sorted_active_viewports.size() - 1; i >= 0; i--) { //to compute parent dependency, must go in reverse draw order
770
Viewport *vp = sorted_active_viewports[i];
771
772
if (vp->update_mode == RS::VIEWPORT_UPDATE_DISABLED) {
773
continue;
774
}
775
776
if (!vp->render_target.is_valid()) {
777
continue;
778
}
779
//ERR_CONTINUE(!vp->render_target.is_valid());
780
781
bool visible = vp->viewport_to_screen_rect != Rect2();
782
783
#ifndef XR_DISABLED
784
if (vp->use_xr) {
785
if (xr_interface.is_valid()) {
786
// Ignore update mode we have to commit frames to our XR interface
787
visible = true;
788
789
// Override our size, make sure it matches our required size and is created as a stereo target
790
Size2 xr_size = xr_interface->get_render_target_size();
791
_viewport_set_size(vp, xr_size.width, xr_size.height, xr_interface->get_view_count());
792
} else {
793
// don't render anything
794
visible = false;
795
vp->size = Size2();
796
}
797
} else
798
#endif // XR_DISABLED
799
{
800
if (vp->update_mode == RS::VIEWPORT_UPDATE_ALWAYS || vp->update_mode == RS::VIEWPORT_UPDATE_ONCE) {
801
visible = true;
802
}
803
804
if (vp->update_mode == RS::VIEWPORT_UPDATE_WHEN_VISIBLE && RSG::texture_storage->render_target_was_used(vp->render_target)) {
805
visible = true;
806
}
807
808
if (vp->update_mode == RS::VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE) {
809
Viewport *parent = viewport_owner.get_or_null(vp->parent);
810
if (parent && parent->last_pass == draw_viewports_pass) {
811
visible = true;
812
}
813
}
814
}
815
816
visible = visible && vp->size.x > 1 && vp->size.y > 1;
817
818
if (visible) {
819
vp->last_pass = draw_viewports_pass;
820
}
821
}
822
823
int vertices_drawn = 0;
824
int objects_drawn = 0;
825
int draw_calls_used = 0;
826
827
for (int i = 0; i < sorted_active_viewports.size(); i++) {
828
// TODO Somehow print the index
829
GodotProfileZone("render viewport");
830
831
Viewport *vp = sorted_active_viewports[i];
832
833
if (vp->last_pass != draw_viewports_pass) {
834
continue; //should not draw
835
}
836
837
RENDER_TIMESTAMP("> Render Viewport " + itos(i));
838
839
RSG::texture_storage->render_target_set_as_unused(vp->render_target);
840
#ifndef XR_DISABLED
841
if (vp->use_xr && xr_interface.is_valid()) {
842
// Inform XR interface we're about to render its viewport,
843
// if this returns false we don't render.
844
// This usually is a result of the player taking off their headset and OpenXR telling us to skip
845
// rendering frames.
846
if (xr_interface->pre_draw_viewport(vp->render_target)) {
847
RSG::texture_storage->render_target_set_override(vp->render_target,
848
xr_interface->get_color_texture(),
849
xr_interface->get_depth_texture(),
850
xr_interface->get_velocity_texture(),
851
xr_interface->get_velocity_depth_texture());
852
853
RSG::texture_storage->render_target_set_velocity_target_size(vp->render_target, xr_interface->get_velocity_target_size());
854
855
if (xr_interface->get_velocity_texture().is_valid()) {
856
_viewport_set_force_motion_vectors(vp, true);
857
} else {
858
_viewport_set_force_motion_vectors(vp, false);
859
}
860
861
RSG::texture_storage->render_target_set_render_region(vp->render_target, xr_interface->get_render_region());
862
863
// render...
864
RSG::scene->set_debug_draw_mode(vp->debug_draw);
865
866
// and draw viewport
867
_draw_viewport(vp);
868
869
// commit our eyes
870
Vector<BlitToScreen> blits = xr_interface->post_draw_viewport(vp->render_target, vp->viewport_to_screen_rect);
871
if (vp->viewport_to_screen != DisplayServer::INVALID_WINDOW_ID) {
872
if (RSG::rasterizer->is_opengl()) {
873
if (blits.size() > 0) {
874
RSG::rasterizer->blit_render_targets_to_screen(vp->viewport_to_screen, blits.ptr(), blits.size());
875
RSG::rasterizer->gl_end_frame(p_swap_buffers);
876
}
877
} else if (blits.size() > 0) {
878
if (!blit_to_screen_list.has(vp->viewport_to_screen)) {
879
blit_to_screen_list[vp->viewport_to_screen] = Vector<BlitToScreen>();
880
}
881
882
for (int b = 0; b < blits.size(); b++) {
883
blit_to_screen_list[vp->viewport_to_screen].push_back(blits[b]);
884
}
885
}
886
}
887
}
888
} else
889
#endif // XR_DISABLED
890
{
891
RSG::scene->set_debug_draw_mode(vp->debug_draw);
892
893
// render standard mono camera
894
_draw_viewport(vp);
895
896
if (vp->viewport_to_screen != DisplayServer::INVALID_WINDOW_ID && (!vp->viewport_render_direct_to_screen || !RSG::rasterizer->is_low_end())) {
897
//copy to screen if set as such
898
BlitToScreen blit;
899
blit.render_target = vp->render_target;
900
if (vp->viewport_to_screen_rect != Rect2()) {
901
blit.dst_rect = vp->viewport_to_screen_rect;
902
} else {
903
blit.dst_rect.position = Vector2();
904
blit.dst_rect.size = vp->size;
905
}
906
907
if (RSG::rasterizer->is_opengl()) {
908
RSG::rasterizer->blit_render_targets_to_screen(vp->viewport_to_screen, &blit, 1);
909
RSG::rasterizer->gl_end_frame(p_swap_buffers);
910
} else {
911
Vector<BlitToScreen> *blits = blit_to_screen_list.getptr(vp->viewport_to_screen);
912
if (blits == nullptr) {
913
blits = &blit_to_screen_list.insert(vp->viewport_to_screen, Vector<BlitToScreen>())->value;
914
}
915
blits->push_back(blit);
916
}
917
}
918
}
919
920
if (vp->update_mode == RS::VIEWPORT_UPDATE_ONCE) {
921
vp->update_mode = RS::VIEWPORT_UPDATE_DISABLED;
922
}
923
924
RENDER_TIMESTAMP("< Render Viewport " + itos(i));
925
926
// 3D render info.
927
objects_drawn += vp->render_info.info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME] + vp->render_info.info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME];
928
vertices_drawn += vp->render_info.info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] + vp->render_info.info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME];
929
draw_calls_used += vp->render_info.info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME] + vp->render_info.info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME];
930
// 2D render info.
931
objects_drawn += vp->render_info.info[RS::VIEWPORT_RENDER_INFO_TYPE_CANVAS][RS::VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME];
932
vertices_drawn += vp->render_info.info[RS::VIEWPORT_RENDER_INFO_TYPE_CANVAS][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME];
933
draw_calls_used += vp->render_info.info[RS::VIEWPORT_RENDER_INFO_TYPE_CANVAS][RS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME];
934
}
935
936
RSG::scene->set_debug_draw_mode(RS::VIEWPORT_DEBUG_DRAW_DISABLED);
937
938
total_objects_drawn = objects_drawn;
939
total_vertices_drawn = vertices_drawn;
940
total_draw_calls_used = draw_calls_used;
941
942
RENDER_TIMESTAMP("< Render Viewports");
943
944
GodotProfileZoneGrouped(_profile_zone, "rasterizer->blit_render_targets_to_screen");
945
if (p_swap_buffers && !blit_to_screen_list.is_empty()) {
946
for (const KeyValue<int, Vector<BlitToScreen>> &E : blit_to_screen_list) {
947
RSG::rasterizer->blit_render_targets_to_screen(E.key, E.value.ptr(), E.value.size());
948
}
949
}
950
}
951
952
RID RendererViewport::viewport_allocate() {
953
return viewport_owner.allocate_rid();
954
}
955
956
void RendererViewport::viewport_initialize(RID p_rid) {
957
viewport_owner.initialize_rid(p_rid);
958
Viewport *viewport = viewport_owner.get_or_null(p_rid);
959
viewport->self = p_rid;
960
viewport->render_target = RSG::texture_storage->render_target_create();
961
viewport->shadow_atlas = RSG::light_storage->shadow_atlas_create();
962
viewport->viewport_render_direct_to_screen = false;
963
964
viewport->fsr_enabled = !RSG::rasterizer->is_low_end() && !viewport->disable_3d;
965
}
966
967
#ifndef XR_DISABLED
968
void RendererViewport::viewport_set_use_xr(RID p_viewport, bool p_use_xr) {
969
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
970
ERR_FAIL_NULL(viewport);
971
972
if (viewport->use_xr == p_use_xr) {
973
return;
974
}
975
976
viewport->use_xr = p_use_xr;
977
978
// Re-configure the 3D render buffers when disabling XR. They'll get
979
// re-configured when enabling XR in draw_viewports().
980
if (!p_use_xr) {
981
viewport->view_count = 1;
982
_configure_3d_render_buffers(viewport);
983
}
984
}
985
#endif // !XR_DISABLED
986
987
void RendererViewport::viewport_set_scaling_3d_mode(RID p_viewport, RS::ViewportScaling3DMode p_mode) {
988
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
989
ERR_FAIL_NULL(viewport);
990
#ifdef DEBUG_ENABLED
991
const String rendering_method = OS::get_singleton()->get_current_rendering_method();
992
if (rendering_method != "forward_plus") {
993
if (p_mode == RS::VIEWPORT_SCALING_3D_MODE_FSR) {
994
WARN_PRINT_ONCE_ED("FSR1 3D scaling is only available when using the Forward+ renderer.");
995
}
996
if (p_mode == RS::VIEWPORT_SCALING_3D_MODE_FSR2) {
997
WARN_PRINT_ONCE_ED("FSR2 3D scaling is only available when using the Forward+ renderer.");
998
}
999
if (p_mode == RS::VIEWPORT_SCALING_3D_MODE_METALFX_TEMPORAL) {
1000
WARN_PRINT_ONCE_ED("MetalFX Temporal 3D scaling is only available when using the Forward+ renderer.");
1001
}
1002
}
1003
if (rendering_method == "gl_compatibility" && p_mode == RS::VIEWPORT_SCALING_3D_MODE_METALFX_SPATIAL) {
1004
WARN_PRINT_ONCE_ED("MetalFX Spatial 3D scaling is only available when using the Forward+ or Mobile renderer.");
1005
}
1006
#endif
1007
1008
if (viewport->scaling_3d_mode == p_mode) {
1009
return;
1010
}
1011
1012
bool motion_vectors_before = _viewport_requires_motion_vectors(viewport);
1013
viewport->scaling_3d_mode = p_mode;
1014
1015
bool motion_vectors_after = _viewport_requires_motion_vectors(viewport);
1016
if (motion_vectors_before != motion_vectors_after) {
1017
num_viewports_with_motion_vectors += motion_vectors_after ? 1 : -1;
1018
}
1019
1020
_configure_3d_render_buffers(viewport);
1021
}
1022
1023
void RendererViewport::viewport_set_fsr_sharpness(RID p_viewport, float p_sharpness) {
1024
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1025
ERR_FAIL_NULL(viewport);
1026
1027
viewport->fsr_sharpness = p_sharpness;
1028
_configure_3d_render_buffers(viewport);
1029
}
1030
1031
void RendererViewport::viewport_set_texture_mipmap_bias(RID p_viewport, float p_mipmap_bias) {
1032
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1033
ERR_FAIL_NULL(viewport);
1034
1035
viewport->texture_mipmap_bias = p_mipmap_bias;
1036
_configure_3d_render_buffers(viewport);
1037
}
1038
1039
void RendererViewport::viewport_set_anisotropic_filtering_level(RID p_viewport, RS::ViewportAnisotropicFiltering p_anisotropic_filtering_level) {
1040
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1041
ERR_FAIL_NULL(viewport);
1042
1043
viewport->anisotropic_filtering_level = p_anisotropic_filtering_level;
1044
_configure_3d_render_buffers(viewport);
1045
}
1046
1047
void RendererViewport::viewport_set_scaling_3d_scale(RID p_viewport, float p_scaling_3d_scale) {
1048
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1049
ERR_FAIL_NULL(viewport);
1050
1051
// Clamp to reasonable values that are actually useful.
1052
// Values above 2.0 don't serve a practical purpose since the viewport
1053
// isn't displayed with mipmaps.
1054
if (viewport->scaling_3d_scale == CLAMP(p_scaling_3d_scale, 0.1, 2.0)) {
1055
return;
1056
}
1057
1058
viewport->scaling_3d_scale = CLAMP(p_scaling_3d_scale, 0.1, 2.0);
1059
_configure_3d_render_buffers(viewport);
1060
}
1061
1062
void RendererViewport::viewport_set_size(RID p_viewport, int p_width, int p_height) {
1063
ERR_FAIL_COND(p_width < 0 || p_height < 0);
1064
1065
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1066
ERR_FAIL_NULL(viewport);
1067
ERR_FAIL_COND_MSG(viewport->use_xr, "Cannot set viewport size when using XR");
1068
1069
_viewport_set_size(viewport, p_width, p_height, 1);
1070
}
1071
1072
void RendererViewport::_viewport_set_size(Viewport *p_viewport, int p_width, int p_height, uint32_t p_view_count) {
1073
Size2i new_size(p_width, p_height);
1074
if (p_viewport->size != new_size || p_viewport->view_count != p_view_count) {
1075
p_viewport->size = new_size;
1076
p_viewport->view_count = p_view_count;
1077
1078
RSG::texture_storage->render_target_set_size(p_viewport->render_target, p_width, p_height, p_view_count);
1079
_configure_3d_render_buffers(p_viewport);
1080
1081
p_viewport->occlusion_buffer_dirty = true;
1082
}
1083
}
1084
1085
bool RendererViewport::_viewport_requires_motion_vectors(Viewport *p_viewport) {
1086
return p_viewport->use_taa ||
1087
RS::scaling_3d_mode_type(p_viewport->scaling_3d_mode) == RS::VIEWPORT_SCALING_3D_TYPE_TEMPORAL ||
1088
p_viewport->debug_draw == RenderingServer::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS || p_viewport->force_motion_vectors;
1089
}
1090
1091
void RendererViewport::viewport_set_active(RID p_viewport, bool p_active) {
1092
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1093
ERR_FAIL_NULL(viewport);
1094
1095
if (p_active) {
1096
ERR_FAIL_COND_MSG(active_viewports.has(viewport), "Can't make active a Viewport that is already active.");
1097
viewport->occlusion_buffer_dirty = true;
1098
active_viewports.push_back(viewport);
1099
} else {
1100
active_viewports.erase(viewport);
1101
}
1102
1103
sorted_active_viewports_dirty = true;
1104
}
1105
1106
void RendererViewport::viewport_set_parent_viewport(RID p_viewport, RID p_parent_viewport) {
1107
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1108
ERR_FAIL_NULL(viewport);
1109
1110
viewport->parent = p_parent_viewport;
1111
}
1112
1113
void RendererViewport::viewport_set_clear_mode(RID p_viewport, RS::ViewportClearMode p_clear_mode) {
1114
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1115
ERR_FAIL_NULL(viewport);
1116
1117
viewport->clear_mode = p_clear_mode;
1118
}
1119
1120
void RendererViewport::viewport_attach_to_screen(RID p_viewport, const Rect2 &p_rect, DisplayServer::WindowID p_screen) {
1121
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1122
ERR_FAIL_NULL(viewport);
1123
1124
if (p_screen != DisplayServer::INVALID_WINDOW_ID) {
1125
// If using OpenGL we can optimize this operation by rendering directly to system_fbo
1126
// instead of rendering to fbo and copying to system_fbo after
1127
if (RSG::rasterizer->is_low_end() && viewport->viewport_render_direct_to_screen) {
1128
RSG::texture_storage->render_target_set_size(viewport->render_target, p_rect.size.x, p_rect.size.y, viewport->view_count);
1129
RSG::texture_storage->render_target_set_position(viewport->render_target, p_rect.position.x, p_rect.position.y);
1130
}
1131
1132
viewport->viewport_to_screen_rect = p_rect;
1133
viewport->viewport_to_screen = p_screen;
1134
} else {
1135
// if render_direct_to_screen was used, reset size and position
1136
if (RSG::rasterizer->is_low_end() && viewport->viewport_render_direct_to_screen) {
1137
RSG::texture_storage->render_target_set_position(viewport->render_target, 0, 0);
1138
RSG::texture_storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y, viewport->view_count);
1139
}
1140
1141
viewport->viewport_to_screen_rect = Rect2();
1142
viewport->viewport_to_screen = DisplayServer::INVALID_WINDOW_ID;
1143
}
1144
}
1145
1146
void RendererViewport::viewport_set_render_direct_to_screen(RID p_viewport, bool p_enable) {
1147
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1148
ERR_FAIL_NULL(viewport);
1149
1150
if (p_enable == viewport->viewport_render_direct_to_screen) {
1151
return;
1152
}
1153
1154
// if disabled, reset render_target size and position
1155
if (!p_enable) {
1156
RSG::texture_storage->render_target_set_position(viewport->render_target, 0, 0);
1157
RSG::texture_storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y, viewport->view_count);
1158
}
1159
1160
RSG::texture_storage->render_target_set_direct_to_screen(viewport->render_target, p_enable);
1161
viewport->viewport_render_direct_to_screen = p_enable;
1162
1163
// if attached to screen already, setup screen size and position, this needs to happen after setting flag to avoid an unnecessary buffer allocation
1164
if (RSG::rasterizer->is_low_end() && viewport->viewport_to_screen_rect != Rect2() && p_enable) {
1165
RSG::texture_storage->render_target_set_size(viewport->render_target, viewport->viewport_to_screen_rect.size.x, viewport->viewport_to_screen_rect.size.y, viewport->view_count);
1166
RSG::texture_storage->render_target_set_position(viewport->render_target, viewport->viewport_to_screen_rect.position.x, viewport->viewport_to_screen_rect.position.y);
1167
}
1168
}
1169
1170
void RendererViewport::viewport_set_update_mode(RID p_viewport, RS::ViewportUpdateMode p_mode) {
1171
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1172
ERR_FAIL_NULL(viewport);
1173
1174
viewport->update_mode = p_mode;
1175
}
1176
1177
RS::ViewportUpdateMode RendererViewport::viewport_get_update_mode(RID p_viewport) const {
1178
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1179
ERR_FAIL_NULL_V(viewport, RS::VIEWPORT_UPDATE_DISABLED);
1180
1181
return viewport->update_mode;
1182
}
1183
1184
RID RendererViewport::viewport_get_render_target(RID p_viewport) const {
1185
const Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1186
ERR_FAIL_NULL_V(viewport, RID());
1187
1188
return viewport->render_target;
1189
}
1190
1191
RID RendererViewport::viewport_get_texture(RID p_viewport) const {
1192
const Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1193
ERR_FAIL_NULL_V(viewport, RID());
1194
1195
return RSG::texture_storage->render_target_get_texture(viewport->render_target);
1196
}
1197
1198
RID RendererViewport::viewport_get_occluder_debug_texture(RID p_viewport) const {
1199
const Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1200
ERR_FAIL_NULL_V(viewport, RID());
1201
1202
if (viewport->use_occlusion_culling && viewport->debug_draw == RenderingServer::VIEWPORT_DEBUG_DRAW_OCCLUDERS) {
1203
return RendererSceneOcclusionCull::get_singleton()->buffer_get_debug_texture(p_viewport);
1204
}
1205
return RID();
1206
}
1207
1208
void RendererViewport::viewport_set_prev_camera_data(RID p_viewport, const RendererSceneRender::CameraData *p_camera_data) {
1209
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1210
ERR_FAIL_NULL(viewport);
1211
uint64_t frame = RSG::rasterizer->get_frame_number();
1212
if (viewport->prev_camera_data_frame != frame) {
1213
viewport->prev_camera_data = *p_camera_data;
1214
viewport->prev_camera_data_frame = frame;
1215
}
1216
}
1217
1218
const RendererSceneRender::CameraData *RendererViewport::viewport_get_prev_camera_data(RID p_viewport) {
1219
const Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1220
ERR_FAIL_NULL_V(viewport, nullptr);
1221
return &viewport->prev_camera_data;
1222
}
1223
1224
void RendererViewport::viewport_set_disable_2d(RID p_viewport, bool p_disable) {
1225
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1226
ERR_FAIL_NULL(viewport);
1227
1228
viewport->disable_2d = p_disable;
1229
}
1230
1231
void RendererViewport::viewport_set_environment_mode(RID p_viewport, RS::ViewportEnvironmentMode p_mode) {
1232
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1233
ERR_FAIL_NULL(viewport);
1234
1235
viewport->disable_environment = p_mode;
1236
}
1237
1238
bool RendererViewport::viewport_is_environment_disabled(Viewport *viewport) {
1239
ERR_FAIL_NULL_V(viewport, false);
1240
1241
if (viewport->parent.is_valid() && viewport->disable_environment == RS::VIEWPORT_ENVIRONMENT_INHERIT) {
1242
Viewport *parent = viewport_owner.get_or_null(viewport->parent);
1243
return viewport_is_environment_disabled(parent);
1244
}
1245
return viewport->disable_environment == RS::VIEWPORT_ENVIRONMENT_DISABLED;
1246
}
1247
1248
void RendererViewport::viewport_set_disable_3d(RID p_viewport, bool p_disable) {
1249
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1250
ERR_FAIL_NULL(viewport);
1251
1252
viewport->disable_3d = p_disable;
1253
}
1254
1255
void RendererViewport::viewport_attach_camera(RID p_viewport, RID p_camera) {
1256
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1257
ERR_FAIL_NULL(viewport);
1258
1259
viewport->camera = p_camera;
1260
}
1261
1262
void RendererViewport::viewport_set_scenario(RID p_viewport, RID p_scenario) {
1263
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1264
ERR_FAIL_NULL(viewport);
1265
1266
if (viewport->scenario.is_valid()) {
1267
RSG::scene->scenario_remove_viewport_visibility_mask(viewport->scenario, p_viewport);
1268
}
1269
1270
viewport->scenario = p_scenario;
1271
if (viewport->use_occlusion_culling) {
1272
RendererSceneOcclusionCull::get_singleton()->buffer_set_scenario(p_viewport, p_scenario);
1273
}
1274
}
1275
1276
void RendererViewport::viewport_attach_canvas(RID p_viewport, RID p_canvas) {
1277
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1278
ERR_FAIL_NULL(viewport);
1279
1280
ERR_FAIL_COND(viewport->canvas_map.has(p_canvas));
1281
RendererCanvasCull::Canvas *canvas = RSG::canvas->canvas_owner.get_or_null(p_canvas);
1282
ERR_FAIL_NULL(canvas);
1283
1284
canvas->viewports.insert(p_viewport);
1285
viewport->canvas_map[p_canvas] = Viewport::CanvasData();
1286
viewport->canvas_map[p_canvas].layer = 0;
1287
viewport->canvas_map[p_canvas].sublayer = 0;
1288
viewport->canvas_map[p_canvas].canvas = canvas;
1289
}
1290
1291
void RendererViewport::viewport_remove_canvas(RID p_viewport, RID p_canvas) {
1292
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1293
ERR_FAIL_NULL(viewport);
1294
1295
RendererCanvasCull::Canvas *canvas = RSG::canvas->canvas_owner.get_or_null(p_canvas);
1296
ERR_FAIL_NULL(canvas);
1297
1298
viewport->canvas_map.erase(p_canvas);
1299
canvas->viewports.erase(p_viewport);
1300
}
1301
1302
void RendererViewport::viewport_set_canvas_transform(RID p_viewport, RID p_canvas, const Transform2D &p_offset) {
1303
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1304
ERR_FAIL_NULL(viewport);
1305
1306
ERR_FAIL_COND(!viewport->canvas_map.has(p_canvas));
1307
viewport->canvas_map[p_canvas].transform = p_offset;
1308
}
1309
1310
void RendererViewport::viewport_set_transparent_background(RID p_viewport, bool p_enabled) {
1311
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1312
ERR_FAIL_NULL(viewport);
1313
if (viewport->transparent_bg == p_enabled) {
1314
return;
1315
}
1316
1317
RSG::texture_storage->render_target_set_transparent(viewport->render_target, p_enabled);
1318
viewport->transparent_bg = p_enabled;
1319
}
1320
1321
void RendererViewport::viewport_set_global_canvas_transform(RID p_viewport, const Transform2D &p_transform) {
1322
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1323
ERR_FAIL_NULL(viewport);
1324
1325
viewport->global_transform = p_transform;
1326
}
1327
1328
void RendererViewport::viewport_set_canvas_stacking(RID p_viewport, RID p_canvas, int p_layer, int p_sublayer) {
1329
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1330
ERR_FAIL_NULL(viewport);
1331
1332
ERR_FAIL_COND(!viewport->canvas_map.has(p_canvas));
1333
viewport->canvas_map[p_canvas].layer = p_layer;
1334
viewport->canvas_map[p_canvas].sublayer = p_sublayer;
1335
}
1336
1337
void RendererViewport::viewport_set_positional_shadow_atlas_size(RID p_viewport, int p_size, bool p_16_bits) {
1338
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1339
ERR_FAIL_NULL(viewport);
1340
1341
viewport->shadow_atlas_size = p_size;
1342
viewport->shadow_atlas_16_bits = p_16_bits;
1343
1344
RSG::light_storage->shadow_atlas_set_size(viewport->shadow_atlas, viewport->shadow_atlas_size, viewport->shadow_atlas_16_bits);
1345
}
1346
1347
void RendererViewport::viewport_set_positional_shadow_atlas_quadrant_subdivision(RID p_viewport, int p_quadrant, int p_subdiv) {
1348
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1349
ERR_FAIL_NULL(viewport);
1350
1351
RSG::light_storage->shadow_atlas_set_quadrant_subdivision(viewport->shadow_atlas, p_quadrant, p_subdiv);
1352
}
1353
1354
void RendererViewport::viewport_set_msaa_2d(RID p_viewport, RS::ViewportMSAA p_msaa) {
1355
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1356
ERR_FAIL_NULL(viewport);
1357
1358
if (viewport->msaa_2d == p_msaa) {
1359
return;
1360
}
1361
viewport->msaa_2d = p_msaa;
1362
RSG::texture_storage->render_target_set_msaa(viewport->render_target, p_msaa);
1363
}
1364
1365
void RendererViewport::viewport_set_msaa_3d(RID p_viewport, RS::ViewportMSAA p_msaa) {
1366
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1367
ERR_FAIL_NULL(viewport);
1368
1369
if (viewport->msaa_3d == p_msaa) {
1370
return;
1371
}
1372
viewport->msaa_3d = p_msaa;
1373
_configure_3d_render_buffers(viewport);
1374
}
1375
1376
void RendererViewport::viewport_set_use_hdr_2d(RID p_viewport, bool p_use_hdr_2d) {
1377
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1378
ERR_FAIL_NULL(viewport);
1379
1380
if (viewport->use_hdr_2d == p_use_hdr_2d) {
1381
return;
1382
}
1383
viewport->use_hdr_2d = p_use_hdr_2d;
1384
RSG::texture_storage->render_target_set_use_hdr(viewport->render_target, p_use_hdr_2d);
1385
_configure_3d_render_buffers(viewport);
1386
}
1387
1388
bool RendererViewport::viewport_is_using_hdr_2d(RID p_viewport) const {
1389
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1390
ERR_FAIL_NULL_V(viewport, false);
1391
1392
return viewport->use_hdr_2d;
1393
}
1394
1395
void RendererViewport::viewport_set_screen_space_aa(RID p_viewport, RS::ViewportScreenSpaceAA p_mode) {
1396
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1397
ERR_FAIL_NULL(viewport);
1398
#ifdef DEBUG_ENABLED
1399
if (OS::get_singleton()->get_current_rendering_method() == "gl_compatibility" && p_mode != RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED) {
1400
WARN_PRINT_ONCE_ED("Screen-space AA is only available when using the Forward+ or Mobile renderer.");
1401
}
1402
#endif
1403
1404
if (viewport->screen_space_aa == p_mode) {
1405
return;
1406
}
1407
viewport->screen_space_aa = p_mode;
1408
_configure_3d_render_buffers(viewport);
1409
}
1410
1411
void RendererViewport::viewport_set_use_taa(RID p_viewport, bool p_use_taa) {
1412
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1413
ERR_FAIL_NULL(viewport);
1414
#ifdef DEBUG_ENABLED
1415
if (OS::get_singleton()->get_current_rendering_method() != "forward_plus") {
1416
WARN_PRINT_ONCE_ED("TAA is only available when using the Forward+ renderer.");
1417
}
1418
#endif
1419
1420
if (viewport->use_taa == p_use_taa) {
1421
return;
1422
}
1423
1424
bool motion_vectors_before = _viewport_requires_motion_vectors(viewport);
1425
viewport->use_taa = p_use_taa;
1426
1427
bool motion_vectors_after = _viewport_requires_motion_vectors(viewport);
1428
if (motion_vectors_before != motion_vectors_after) {
1429
num_viewports_with_motion_vectors += motion_vectors_after ? 1 : -1;
1430
}
1431
1432
_configure_3d_render_buffers(viewport);
1433
}
1434
1435
void RendererViewport::viewport_set_use_debanding(RID p_viewport, bool p_use_debanding) {
1436
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1437
ERR_FAIL_NULL(viewport);
1438
1439
if (viewport->use_debanding == p_use_debanding) {
1440
return;
1441
}
1442
viewport->use_debanding = p_use_debanding;
1443
RSG::texture_storage->render_target_set_use_debanding(viewport->render_target, p_use_debanding);
1444
_configure_3d_render_buffers(viewport);
1445
}
1446
1447
void RendererViewport::viewport_set_force_motion_vectors(RID p_viewport, bool p_force_motion_vectors) {
1448
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1449
ERR_FAIL_NULL(viewport);
1450
1451
_viewport_set_force_motion_vectors(viewport, p_force_motion_vectors);
1452
}
1453
1454
void RendererViewport::_viewport_set_force_motion_vectors(RendererViewport::Viewport *p_viewport, bool p_force_motion_vectors) {
1455
if (p_viewport->force_motion_vectors == p_force_motion_vectors) {
1456
return;
1457
}
1458
1459
bool motion_vectors_before = _viewport_requires_motion_vectors(p_viewport);
1460
p_viewport->force_motion_vectors = p_force_motion_vectors;
1461
1462
bool motion_vectors_after = _viewport_requires_motion_vectors(p_viewport);
1463
if (motion_vectors_before != motion_vectors_after) {
1464
num_viewports_with_motion_vectors += motion_vectors_after ? 1 : -1;
1465
}
1466
1467
_configure_3d_render_buffers(p_viewport);
1468
}
1469
1470
void RendererViewport::viewport_set_use_occlusion_culling(RID p_viewport, bool p_use_occlusion_culling) {
1471
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1472
ERR_FAIL_NULL(viewport);
1473
1474
if (viewport->use_occlusion_culling == p_use_occlusion_culling) {
1475
return;
1476
}
1477
viewport->use_occlusion_culling = p_use_occlusion_culling;
1478
1479
if (viewport->use_occlusion_culling) {
1480
RendererSceneOcclusionCull::get_singleton()->add_buffer(p_viewport);
1481
RendererSceneOcclusionCull::get_singleton()->buffer_set_scenario(p_viewport, viewport->scenario);
1482
} else {
1483
RendererSceneOcclusionCull::get_singleton()->remove_buffer(p_viewport);
1484
}
1485
1486
viewport->occlusion_buffer_dirty = true;
1487
}
1488
1489
void RendererViewport::viewport_set_occlusion_rays_per_thread(int p_rays_per_thread) {
1490
if (occlusion_rays_per_thread == p_rays_per_thread) {
1491
return;
1492
}
1493
1494
occlusion_rays_per_thread = p_rays_per_thread;
1495
1496
for (int i = 0; i < active_viewports.size(); i++) {
1497
active_viewports[i]->occlusion_buffer_dirty = true;
1498
}
1499
}
1500
1501
void RendererViewport::viewport_set_occlusion_culling_build_quality(RS::ViewportOcclusionCullingBuildQuality p_quality) {
1502
RendererSceneOcclusionCull::get_singleton()->set_build_quality(p_quality);
1503
}
1504
1505
void RendererViewport::viewport_set_mesh_lod_threshold(RID p_viewport, float p_pixels) {
1506
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1507
ERR_FAIL_NULL(viewport);
1508
1509
viewport->mesh_lod_threshold = p_pixels;
1510
}
1511
1512
int RendererViewport::viewport_get_render_info(RID p_viewport, RS::ViewportRenderInfoType p_type, RS::ViewportRenderInfo p_info) {
1513
ERR_FAIL_INDEX_V(p_type, RS::VIEWPORT_RENDER_INFO_TYPE_MAX, -1);
1514
ERR_FAIL_INDEX_V(p_info, RS::VIEWPORT_RENDER_INFO_MAX, -1);
1515
1516
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1517
if (!viewport) {
1518
return 0; //there should be a lock here..
1519
}
1520
1521
return viewport->render_info.info[p_type][p_info];
1522
}
1523
1524
void RendererViewport::viewport_set_debug_draw(RID p_viewport, RS::ViewportDebugDraw p_draw) {
1525
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1526
ERR_FAIL_NULL(viewport);
1527
1528
bool motion_vectors_before = _viewport_requires_motion_vectors(viewport);
1529
viewport->debug_draw = p_draw;
1530
1531
bool motion_vectors_after = _viewport_requires_motion_vectors(viewport);
1532
if (motion_vectors_before != motion_vectors_after) {
1533
num_viewports_with_motion_vectors += motion_vectors_after ? 1 : -1;
1534
}
1535
}
1536
1537
void RendererViewport::viewport_set_measure_render_time(RID p_viewport, bool p_enable) {
1538
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1539
ERR_FAIL_NULL(viewport);
1540
1541
viewport->measure_render_time = p_enable;
1542
}
1543
1544
float RendererViewport::viewport_get_measured_render_time_cpu(RID p_viewport) const {
1545
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1546
ERR_FAIL_NULL_V(viewport, 0);
1547
1548
return double(viewport->time_cpu_end - viewport->time_cpu_begin) / 1000.0;
1549
}
1550
1551
float RendererViewport::viewport_get_measured_render_time_gpu(RID p_viewport) const {
1552
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1553
ERR_FAIL_NULL_V(viewport, 0);
1554
1555
return double((viewport->time_gpu_end - viewport->time_gpu_begin) / 1000) / 1000.0;
1556
}
1557
1558
void RendererViewport::viewport_set_snap_2d_transforms_to_pixel(RID p_viewport, bool p_enabled) {
1559
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1560
ERR_FAIL_NULL(viewport);
1561
viewport->snap_2d_transforms_to_pixel = p_enabled;
1562
}
1563
1564
void RendererViewport::viewport_set_snap_2d_vertices_to_pixel(RID p_viewport, bool p_enabled) {
1565
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1566
ERR_FAIL_NULL(viewport);
1567
viewport->snap_2d_vertices_to_pixel = p_enabled;
1568
}
1569
1570
void RendererViewport::viewport_set_default_canvas_item_texture_filter(RID p_viewport, RS::CanvasItemTextureFilter p_filter) {
1571
ERR_FAIL_COND_MSG(p_filter == RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, "Viewport does not accept DEFAULT as texture filter (it's the topmost choice already).)");
1572
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1573
ERR_FAIL_NULL(viewport);
1574
1575
viewport->texture_filter = p_filter;
1576
}
1577
void RendererViewport::viewport_set_default_canvas_item_texture_repeat(RID p_viewport, RS::CanvasItemTextureRepeat p_repeat) {
1578
ERR_FAIL_COND_MSG(p_repeat == RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, "Viewport does not accept DEFAULT as texture repeat (it's the topmost choice already).)");
1579
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1580
ERR_FAIL_NULL(viewport);
1581
1582
viewport->texture_repeat = p_repeat;
1583
}
1584
1585
void RendererViewport::viewport_set_sdf_oversize_and_scale(RID p_viewport, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) {
1586
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1587
ERR_FAIL_NULL(viewport);
1588
1589
RSG::texture_storage->render_target_set_sdf_size_and_scale(viewport->render_target, p_size, p_scale);
1590
}
1591
1592
RID RendererViewport::viewport_find_from_screen_attachment(DisplayServer::WindowID p_id) const {
1593
RID *rids = nullptr;
1594
uint32_t rid_count = viewport_owner.get_rid_count();
1595
rids = (RID *)alloca(sizeof(RID) * rid_count);
1596
viewport_owner.fill_owned_buffer(rids);
1597
for (uint32_t i = 0; i < rid_count; i++) {
1598
Viewport *viewport = viewport_owner.get_or_null(rids[i]);
1599
if (viewport->viewport_to_screen == p_id) {
1600
return rids[i];
1601
}
1602
}
1603
return RID();
1604
}
1605
1606
void RendererViewport::viewport_set_vrs_mode(RID p_viewport, RS::ViewportVRSMode p_mode) {
1607
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1608
ERR_FAIL_NULL(viewport);
1609
1610
RSG::texture_storage->render_target_set_vrs_mode(viewport->render_target, p_mode);
1611
_configure_3d_render_buffers(viewport);
1612
}
1613
1614
void RendererViewport::viewport_set_vrs_update_mode(RID p_viewport, RS::ViewportVRSUpdateMode p_mode) {
1615
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1616
ERR_FAIL_NULL(viewport);
1617
1618
RSG::texture_storage->render_target_set_vrs_update_mode(viewport->render_target, p_mode);
1619
}
1620
1621
void RendererViewport::viewport_set_vrs_texture(RID p_viewport, RID p_texture) {
1622
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1623
ERR_FAIL_NULL(viewport);
1624
1625
RSG::texture_storage->render_target_set_vrs_texture(viewport->render_target, p_texture);
1626
_configure_3d_render_buffers(viewport);
1627
}
1628
1629
bool RendererViewport::free(RID p_rid) {
1630
if (viewport_owner.owns(p_rid)) {
1631
Viewport *viewport = viewport_owner.get_or_null(p_rid);
1632
1633
RSG::texture_storage->render_target_free(viewport->render_target);
1634
RSG::light_storage->shadow_atlas_free(viewport->shadow_atlas);
1635
if (viewport->render_buffers.is_valid()) {
1636
viewport->render_buffers.unref();
1637
}
1638
1639
while (viewport->canvas_map.begin()) {
1640
viewport_remove_canvas(p_rid, viewport->canvas_map.begin()->key);
1641
}
1642
1643
viewport_set_scenario(p_rid, RID());
1644
active_viewports.erase(viewport);
1645
sorted_active_viewports_dirty = true;
1646
1647
if (viewport->use_occlusion_culling) {
1648
RendererSceneOcclusionCull::get_singleton()->remove_buffer(p_rid);
1649
}
1650
1651
if (_viewport_requires_motion_vectors(viewport)) {
1652
num_viewports_with_motion_vectors--;
1653
}
1654
1655
viewport_owner.free(p_rid);
1656
1657
return true;
1658
}
1659
1660
return false;
1661
}
1662
1663
void RendererViewport::handle_timestamp(String p_timestamp, uint64_t p_cpu_time, uint64_t p_gpu_time) {
1664
RID *vp = timestamp_vp_map.getptr(p_timestamp);
1665
if (!vp) {
1666
return;
1667
}
1668
1669
Viewport *viewport = viewport_owner.get_or_null(*vp);
1670
if (!viewport) {
1671
return;
1672
}
1673
1674
if (p_timestamp.begins_with("vp_begin")) {
1675
viewport->time_cpu_begin = p_cpu_time;
1676
viewport->time_gpu_begin = p_gpu_time;
1677
}
1678
1679
if (p_timestamp.begins_with("vp_end")) {
1680
viewport->time_cpu_end = p_cpu_time;
1681
viewport->time_gpu_end = p_gpu_time;
1682
}
1683
}
1684
1685
void RendererViewport::viewport_set_canvas_cull_mask(RID p_viewport, uint32_t p_canvas_cull_mask) {
1686
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
1687
ERR_FAIL_NULL(viewport);
1688
viewport->canvas_cull_mask = p_canvas_cull_mask;
1689
}
1690
1691
// Workaround for setting this on thread.
1692
void RendererViewport::call_set_vsync_mode(DisplayServer::VSyncMode p_mode, DisplayServer::WindowID p_window) {
1693
DisplayServer::get_singleton()->window_set_vsync_mode(p_mode, p_window);
1694
}
1695
1696
int RendererViewport::get_total_objects_drawn() const {
1697
return total_objects_drawn;
1698
}
1699
int RendererViewport::get_total_primitives_drawn() const {
1700
return total_vertices_drawn;
1701
}
1702
int RendererViewport::get_total_draw_calls_used() const {
1703
return total_draw_calls_used;
1704
}
1705
1706
int RendererViewport::get_num_viewports_with_motion_vectors() const {
1707
return num_viewports_with_motion_vectors;
1708
}
1709
1710
RendererViewport::RendererViewport() {
1711
occlusion_rays_per_thread = GLOBAL_GET("rendering/occlusion_culling/occlusion_rays_per_thread");
1712
}
1713
1714