Skip to content

Commit

Permalink
Merge pull request godotengine#11 from Ansraer/ramatak_low_is_high
Browse files Browse the repository at this point in the history
Allow rendering of 3d content at lower resolution
  • Loading branch information
hpvb authored Jul 3, 2023
2 parents e1ebb80 + 42487c1 commit 82e4f08
Show file tree
Hide file tree
Showing 20 changed files with 475 additions and 35 deletions.
7 changes: 7 additions & 0 deletions doc/classes/ProjectSettings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1627,6 +1627,13 @@
Uses a simplified method of generating PVS (potentially visible set) data. The results may not be accurate where more than one portal join adjacent rooms.
[b]Note:[/b] Generally you should only use this option if you encounter bugs when it is set to [code]false[/code], i.e. there are problems with the default method.
</member>
<member name="rendering/quality/3d/resolution_scale" type="float" setter="" getter="" default="1.0">
If set to a value lower than 1.0 the 3D rendering occurs at a lower resolution. 2D is still rendered at full resolution. This setting only applies if MSAA is disabled for the current viewport.
[b]Note:[/b] This changes the width and the height of the 3D resolution. So if you set this setting to 0.5 you only render 1/4 the pixels.
</member>
<member name="rendering/quality/3d/resolution_scale_filter_method" type="int" setter="" getter="" default="1">
The fitlering method that is used when upscaling the 3D image.
</member>
<member name="rendering/quality/depth/hdr" type="bool" setter="" getter="" default="true">
If [code]true[/code], allocates the root [Viewport]'s framebuffer with high dynamic range. High dynamic range allows the use of [Color] values greater than 1. This must be set to [code]true[/code] for glow rendering to work if [member Environment.glow_hdr_threshold] is greater than or equal to [code]1.0[/code].
[b]Note:[/b] Only available on the GLES3 backend.
Expand Down
15 changes: 15 additions & 0 deletions doc/classes/Viewport.xml
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,15 @@
<member name="render_target_v_flip" type="bool" setter="set_vflip" getter="get_vflip" default="false">
If [code]true[/code], the result of rendering will be flipped vertically. Since Viewports in Godot 3.x render upside-down, it's recommended to set this to [code]true[/code] in most situations.
</member>
<member name="resolution_scale_factor" type="float" setter="set_resolution_scale_factor" getter="get_resolution_scale_factor" default="1.0">
Sets a resolution scale factor for the viewport. This makes it possible to render 3d content at a fraction of the original resolution.
</member>
<member name="resolution_scale_filter" type="int" setter="set_resolution_scale_filter" getter="get_resolution_scale_filter" enum="Viewport.ResolutionScaleFilter" default="0">
This changes how the rendered image is filtered when it is upscaled. This defaults to whatever has been configured in the project settings.
</member>
<member name="resolution_scale_mix" type="bool" setter="set_resolution_scale_mix" getter="get_resolution_scale_mix" default="true">
If this is enabled the viewport specific scale factor is multiplied with the global scale factor that has been set in the project settings. If this is disabled the viewport scale overrides the global one for this viewport.
</member>
<member name="shadow_atlas_quad_0" type="int" setter="set_shadow_atlas_quadrant_subdiv" getter="get_shadow_atlas_quadrant_subdiv" enum="Viewport.ShadowAtlasQuadrantSubdiv" default="2">
The subdivision amount of the first quadrant on the shadow atlas.
</member>
Expand Down Expand Up @@ -430,5 +439,11 @@
<constant name="CLEAR_MODE_ONLY_NEXT_FRAME" value="2" enum="ClearMode">
Clear the render target next frame, then switch to [constant CLEAR_MODE_NEVER].
</constant>
<constant name="RESOLUTION_SCALE_FILTER_DEFAULT" value="0" enum="ResolutionScaleFilter">
</constant>
<constant name="RESOLUTION_SCALE_FILTER_LINEAR" value="1" enum="ResolutionScaleFilter">
</constant>
<constant name="RESOLUTION_SCALE_FILTER_NEAREST" value="2" enum="ResolutionScaleFilter">
</constant>
</constants>
</class>
3 changes: 3 additions & 0 deletions drivers/dummy/rasterizer_dummy.h
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,9 @@ class RasterizerStorageDummy : public RasterizerStorage {
RID render_target_create() { return RID(); }
void render_target_set_position(RID p_render_target, int p_x, int p_y) {}
void render_target_set_size(RID p_render_target, int p_width, int p_height) {}
void render_target_set_resolution_scale_mix(RID p_render_target, bool p_mix){};
void render_target_set_resolution_scale_filter(RID p_render_target, VS::ResolutionScaleFilter p_method){};
void render_target_set_resolution_scale_factor(RID p_render_target, float p_factor){};
RID render_target_get_texture(RID p_render_target) const { return RID(); }
uint32_t render_target_get_depth_texture_id(RID p_render_target) const { return 0; }
void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id, unsigned int p_depth_id) {}
Expand Down
61 changes: 58 additions & 3 deletions drivers/gles2/rasterizer_scene_gles2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3262,9 +3262,19 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
bool probe_interior = false;
bool reverse_cull = false;

if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) {
cam_transform.basis.set_axis(1, -cam_transform.basis.get_axis(1));
reverse_cull = true;
bool use_resolution_scale = false;
float final_resolution_scale = global_spatial_resolution_factor;
if (storage->frame.current_rt) {
if (storage->frame.current_rt->spatial_resolution_scale_mix) {
final_resolution_scale = global_spatial_resolution_factor * storage->frame.current_rt->spatial_resolution_scale_factor;
} else {
final_resolution_scale = storage->frame.current_rt->spatial_resolution_scale_factor;
}

if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) {
cam_transform.basis.set_axis(1, -cam_transform.basis.get_axis(1));
reverse_cull = true;
}
}

if (p_reflection_probe.is_valid()) {
Expand All @@ -3289,6 +3299,9 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
current_fb = storage->frame.current_rt->multisample_fbo;
} else if (storage->frame.current_rt->external.fbo != 0) {
current_fb = storage->frame.current_rt->external.fbo;
} else if (final_resolution_scale < 0.95 && !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_DIRECT_TO_SCREEN] && storage->frame.current_rt->msaa == VS::VIEWPORT_MSAA_DISABLED) {
use_resolution_scale = true;
current_fb = storage->frame.current_rt->fbo_small;
} else {
current_fb = storage->frame.current_rt->fbo;
}
Expand All @@ -3305,6 +3318,11 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
}
}

if (use_resolution_scale) {
viewport_width = floor(viewport_width * final_resolution_scale);
viewport_height = floor(viewport_height * final_resolution_scale);
}

state.used_screen_texture = false;
state.viewport_size.x = viewport_width;
state.viewport_size.y = viewport_height;
Expand Down Expand Up @@ -3622,6 +3640,41 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
return;
}

if (use_resolution_scale) {
// copy over to default fbo
glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo);
glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height);
#ifdef XXX_GLES_OVER_GL // broken when using anything other than NEAREST

glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->fbo_small);
glReadBuffer(GL_COLOR_ATTACHMENT0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->fbo);
glBlitFramebuffer(0, 0, viewport_width, viewport_height, 0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST);

glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
#else
glDepthMask(GL_FALSE);
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glDisable(GL_BLEND);
glDepthFunc(GL_LEQUAL);
glColorMask(1, 1, 1, 1);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->color_small);

storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_DISPLAY_TRANSFORM, true);
storage->shaders.copy.bind();
storage->shaders.copy.set_uniform(CopyShaderGLES2::DISPLAY_TRANSFORM, Transform(final_resolution_scale, 0.0, 0.0, 0.0, final_resolution_scale, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0));

storage->bind_quad_array();
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glBindBuffer(GL_ARRAY_BUFFER, 0);
storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_DISPLAY_TRANSFORM, false);
#endif
}

//post process
SECTION_START("POST PROCESS");
TIMESTAMP("post_process");
Expand Down Expand Up @@ -4127,6 +4180,8 @@ void RasterizerSceneGLES2::initialize() {
}

void RasterizerSceneGLES2::iteration() {
global_spatial_resolution_factor = float(GLOBAL_GET("rendering/quality/3d/resolution_scale"));

shadow_filter_mode = ShadowFilterMode(int(GLOBAL_GET("rendering/quality/shadows/filter_mode")));

const int directional_shadow_size_new = next_power_of_2(int(GLOBAL_GET("rendering/quality/directional_shadow/size")));
Expand Down
2 changes: 2 additions & 0 deletions drivers/gles2/rasterizer_scene_gles2.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ class RasterizerSceneGLES2 : public RasterizerScene {
INSTANCE_BONE_BASE = 13,
};

float global_spatial_resolution_factor;

ShadowFilterMode shadow_filter_mode;

RID default_material;
Expand Down
102 changes: 102 additions & 0 deletions drivers/gles2/rasterizer_storage_gles2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5106,6 +5106,68 @@ void RasterizerStorageGLES2::_render_target_allocate(RenderTarget *rt) {
texture_set_flags(rt->texture, texture->flags);
}

{
/* Small Front FBO */

// framebuffer
glGenFramebuffers(1, &rt->fbo_small);
glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo_small);

// color
glGenTextures(1, &rt->color_small);
glBindTexture(GL_TEXTURE_2D, rt->color_small);

glTexImage2D(GL_TEXTURE_2D, 0, color_internal_format, rt->width, rt->height, 0, color_format, color_type, nullptr);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color_small, 0);

// depth

if (config.support_depth_texture) {
glGenTextures(1, &rt->depth_small);
glBindTexture(GL_TEXTURE_2D, rt->depth_small);
glTexImage2D(GL_TEXTURE_2D, 0, config.depth_internalformat, rt->width, rt->height, 0, GL_DEPTH_COMPONENT, config.depth_type, nullptr);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth_small, 0);
} else {
glGenRenderbuffers(1, &rt->depth_small);
glBindRenderbuffer(GL_RENDERBUFFER, rt->depth_small);

glRenderbufferStorage(GL_RENDERBUFFER, config.depth_buffer_internalformat, rt->width, rt->height);

glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth_small);
}

GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);

if (status != GL_FRAMEBUFFER_COMPLETE) {
glDeleteFramebuffers(1, &rt->fbo_small);
if (config.support_depth_texture) {
glDeleteTextures(1, &rt->depth_small);
} else {
glDeleteRenderbuffers(1, &rt->depth_small);
}

glDeleteTextures(1, &rt->color_small);
rt->fbo_small = 0;
rt->color_small = 0;
rt->depth_small = 0;
WARN_PRINT("Could not create alternative small framebuffer!!");
return;
}
}

/* BACK FBO */
/* For MSAA */

Expand Down Expand Up @@ -5353,6 +5415,12 @@ void RasterizerStorageGLES2::_render_target_clear(RenderTarget *rt) {
rt->fbo = 0;
}

if (rt->fbo_small) {
glDeleteFramebuffers(1, &rt->fbo_small);
glDeleteTextures(1, &rt->color_small);
rt->fbo = 0;
}

Texture *tex = texture_owner.get(rt->texture);
tex->alloc_height = 0;
tex->alloc_width = 0;
Expand Down Expand Up @@ -5380,8 +5448,10 @@ void RasterizerStorageGLES2::_render_target_clear(RenderTarget *rt) {
if (rt->depth) {
if (config.support_depth_texture) {
glDeleteTextures(1, &rt->depth);
glDeleteTextures(1, &rt->depth_small);
} else {
glDeleteRenderbuffers(1, &rt->depth);
glDeleteRenderbuffers(1, &rt->depth_small);
}

rt->depth = 0;
Expand Down Expand Up @@ -5707,6 +5777,38 @@ void RasterizerStorageGLES2::render_target_set_sharpen_intensity(RID p_render_ta
rt->sharpen_intensity = p_intensity;
}

void RasterizerStorageGLES2::render_target_set_resolution_scale_mix(RID p_render_target, bool p_mix) {
RenderTarget *rt = render_target_owner.getornull(p_render_target);
ERR_FAIL_COND(!rt);

rt->spatial_resolution_scale_mix = p_mix;
}

void RasterizerStorageGLES2::render_target_set_resolution_scale_filter(RID p_render_target, VS::ResolutionScaleFilter p_method) {
RenderTarget *rt = render_target_owner.getornull(p_render_target);
ERR_FAIL_COND(!rt);

switch (p_method) {
case VS::ResolutionScaleFilter::NEAREST:
rt->spatial_resolution_scale_filter = GL_NEAREST;
break;
case VS::ResolutionScaleFilter::LINEAR:
rt->spatial_resolution_scale_filter = GL_LINEAR;
break;
case VS::ResolutionScaleFilter::DEFAULT:
default:
rt->spatial_resolution_scale_filter = 0;
break;
}
}

void RasterizerStorageGLES2::render_target_set_resolution_scale_factor(RID p_render_target, float p_factor) {
RenderTarget *rt = render_target_owner.getornull(p_render_target);
ERR_FAIL_COND(!rt);

rt->spatial_resolution_scale_factor = p_factor;
}

/* CANVAS SHADOW */

RID RasterizerStorageGLES2::canvas_light_shadow_buffer_create(int p_width) {
Expand Down
18 changes: 18 additions & 0 deletions drivers/gles2/rasterizer_storage_gles2.h
Original file line number Diff line number Diff line change
Expand Up @@ -1181,6 +1181,14 @@ class RasterizerStorageGLES2 : public RasterizerStorage {
GLuint color;
GLuint depth;

bool spatial_resolution_scale_mix;
unsigned int spatial_resolution_scale_filter;
float spatial_resolution_scale_factor;

GLuint fbo_small;
GLuint color_small;
GLuint depth_small;

GLuint multisample_fbo;
GLuint multisample_color;
GLuint multisample_depth;
Expand Down Expand Up @@ -1257,6 +1265,12 @@ class RasterizerStorageGLES2 : public RasterizerStorage {
fbo(0),
color(0),
depth(0),
spatial_resolution_scale_mix(true),
spatial_resolution_scale_filter(0),
spatial_resolution_scale_factor(1.0),
fbo_small(0),
color_small(0),
depth_small(0),
multisample_fbo(0),
multisample_color(0),
multisample_depth(0),
Expand Down Expand Up @@ -1299,6 +1313,10 @@ class RasterizerStorageGLES2 : public RasterizerStorage {
virtual void render_target_set_use_debanding(RID p_render_target, bool p_debanding);
virtual void render_target_set_sharpen_intensity(RID p_render_target, float p_intensity);

virtual void render_target_set_resolution_scale_mix(RID p_render_target, bool p_mix);
virtual void render_target_set_resolution_scale_filter(RID p_render_target, VS::ResolutionScaleFilter p_method);
virtual void render_target_set_resolution_scale_factor(RID p_render_target, float p_factor);

/* CANVAS SHADOW */

struct CanvasLightShadow : public RID_Data {
Expand Down
Loading

0 comments on commit 82e4f08

Please sign in to comment.