From 7da8b012e62a5ec4ae0219ac2c8d93ac0cc41bf3 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Fri, 13 Dec 2013 02:19:57 -0600 Subject: [PATCH] Pulled SSAO out into its own shader to support running at a lower-than-native framebuffer resolution (defaults at half-resolution [SHRenderSSAOResolutionScale=.5] ). This doesn't improve the slow ssao/shadow softening, however, as that bit remains unchanged. --- indra/llrender/llshadermgr.cpp | 2 + indra/llrender/llshadermgr.h | 2 + indra/newview/app_settings/settings_sh.xml | 11 + .../shaders/class1/deferred/SSAOF.glsl | 140 ++++++++++++ .../shaders/class1/deferred/blurLightF.glsl | 34 ++- .../deferred/downsampleDepthNearestF.glsl | 41 ++++ .../class1/deferred/sunLightSSAOF.glsl | 117 +--------- .../class2/deferred/sunLightSSAOF.glsl | 66 +----- indra/newview/llviewercontrol.cpp | 1 + indra/newview/llviewershadermgr.cpp | 25 +++ indra/newview/llviewershadermgr.h | 2 + indra/newview/pipeline.cpp | 210 +++++++++++++++--- indra/newview/pipeline.h | 1 + 13 files changed, 445 insertions(+), 207 deletions(-) create mode 100644 indra/newview/app_settings/shaders/class1/deferred/SSAOF.glsl create mode 100644 indra/newview/app_settings/shaders/class1/deferred/downsampleDepthNearestF.glsl diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 843789ae1..fbb456eed 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -1177,6 +1177,7 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("depth_cutoff"); mReservedUniforms.push_back("norm_cutoff"); mReservedUniforms.push_back("shadow_target_width"); + mReservedUniforms.push_back("downsampled_depth_scale"); llassert(mReservedUniforms.size() == LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH+1); @@ -1195,6 +1196,7 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("dof_height"); mReservedUniforms.push_back("depthMap"); + mReservedUniforms.push_back("depthMapDownsampled"); mReservedUniforms.push_back("shadowMap0"); mReservedUniforms.push_back("shadowMap1"); mReservedUniforms.push_back("shadowMap2"); diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index c13485b71..7dccf47b1 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -136,6 +136,7 @@ public: DEFERRED_DEPTH_CUTOFF, DEFERRED_NORM_CUTOFF, DEFERRED_SHADOW_TARGET_WIDTH, + DEFERRED_DOWNSAMPLED_DEPTH_SCALE, FXAA_TC_SCALE, FXAA_RCP_SCREEN_RES, @@ -152,6 +153,7 @@ public: DOF_HEIGHT, DEFERRED_DEPTH, + DEFERRED_DOWNSAMPLED_DEPTH, DEFERRED_SHADOW0, DEFERRED_SHADOW1, DEFERRED_SHADOW2, diff --git a/indra/newview/app_settings/settings_sh.xml b/indra/newview/app_settings/settings_sh.xml index 998c3ff37..5fb2c4826 100644 --- a/indra/newview/app_settings/settings_sh.xml +++ b/indra/newview/app_settings/settings_sh.xml @@ -229,5 +229,16 @@ Value 1 + SHRenderSSAOResolutionScale + + Comment + SSAO resolution scale. Valid values: 0.01-1.0 + Persist + 1 + Type + F32 + Value + .5 + diff --git a/indra/newview/app_settings/shaders/class1/deferred/SSAOF.glsl b/indra/newview/app_settings/shaders/class1/deferred/SSAOF.glsl new file mode 100644 index 000000000..64c4e41cf --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/SSAOF.glsl @@ -0,0 +1,140 @@ +/** + * @file sunLightF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +//#extension GL_ARB_texture_rectangle : enable + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +VARYING vec2 vary_fragcoord; + +uniform sampler2DRect depthMapDownsampled; +uniform sampler2DRect normalMap; +uniform sampler2D noiseMap; + +uniform vec2 screen_res; +uniform mat4 inv_proj; + +uniform float downsampled_depth_scale; + +uniform float ssao_radius; +uniform float ssao_max_radius; +uniform float ssao_factor; + +vec3 decode_normal (vec2 enc) +{ + vec2 fenc = enc*4-2; + float f = dot(fenc,fenc); + float g = sqrt(1-f/4); + vec3 n; + n.xy = fenc*g; + n.z = 1-f/2; + return n; +} + +vec4 getPosition(vec2 pos_screen) +{ + float depth = texture2DRect(depthMapDownsampled, pos_screen.xy*downsampled_depth_scale).r; + vec2 sc = pos_screen.xy*2.0; + sc /= screen_res; + sc -= vec2(1.0,1.0); + vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); + vec4 pos = inv_proj * ndc; + pos /= pos.w; + pos.w = 1.0; + return pos; +} + +vec2 getKern(int i) +{ + vec2 kern[8]; + // exponentially (^2) distant occlusion samples spread around origin + kern[0] = vec2(-1.0, 0.0) * (0.125*0.125*.9+.1); + kern[1] = vec2(1.0, 0.0) * (0.250*0.250*.9+.1); + kern[2] = vec2(0.0, 1.0) * (0.375*0.375*.9+.1); + kern[3] = vec2(0.0, -1.0) * (0.500*0.500*.9+.1); + kern[4] = vec2(0.7071, 0.7071) * (0.625*0.625*.9+.1); + kern[5] = vec2(-0.7071, -0.7071) * (0.750*0.750*.9+.1); + kern[6] = vec2(-0.7071, 0.7071) * (0.875*0.875*.9+.1); + kern[7] = vec2(0.7071, -0.7071) * (1.000*1.000*.9+.1); + + return kern[i]; +} + +//calculate decreases in ambient lighting when crowded out (SSAO) +float calcAmbientOcclusion(vec4 pos, vec3 norm) +{ + vec2 pos_screen = vary_fragcoord.xy; + vec2 noise_reflect = texture2D(noiseMap, vary_fragcoord.xy/128.0).xy; + + // We treat the first sample as the origin, which definitely doesn't obscure itself thanks to being visible for sampling in the first place. + float points = 1.0; + float angle_hidden = 0.0; + + // use a kernel scale that diminishes with distance. + // a scale of less than 32 is just wasting good samples, though. + float scale = max(32.0, min(ssao_radius / -pos.z, ssao_max_radius)); + + // it was found that keeping # of samples a constant was the fastest, probably due to compiler optimizations (unrolling?) + for (int i = 0; i < 8; i++) + { + vec2 samppos_screen = pos_screen + scale * reflect(getKern(i), noise_reflect); + vec3 samppos_world = getPosition(samppos_screen).xyz; + + vec3 diff = samppos_world - pos.xyz; + + if (diff.z < ssao_factor && diff.z != 0.0) + { + float dist = length(diff); + float angrel = max(0.0, dot(norm.xyz, diff/dist)); + float distrel = 1.0/(1.0+dist*dist); + float samplehidden = min(angrel, distrel); + + angle_hidden += (samplehidden); + points += 1.0; + } + } + + angle_hidden /= points; + float rtn = (1.0 - angle_hidden); + return (rtn * rtn) * (rtn * rtn); //Pow2 to increase darkness to match previous behavior. +} + +void main() +{ + vec2 pos_screen = vary_fragcoord.xy; + + //try doing an unproject here + + vec4 pos = getPosition(pos_screen); + + vec3 norm = texture2DRect(normalMap, pos_screen).xyz; + norm = decode_normal(norm.xy); + + frag_color = vec4(calcAmbientOcclusion(pos,norm),0,0,0); +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl index 369a014fb..80c0c6e7b 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl @@ -38,7 +38,7 @@ uniform sampler2DRect lightMap; uniform float dist_factor; uniform float blur_size; uniform vec2 delta; -uniform vec3 kern[4]; +//uniform vec3 kern[4]; uniform float kern_scale; VARYING vec2 vary_fragcoord; @@ -46,8 +46,14 @@ VARYING vec2 vary_fragcoord; uniform mat4 inv_proj; uniform vec2 screen_res; -vec3 getKern(int i) +vec2 getKern(int i) { + vec2 kern[4]; + + kern[0] = vec2(0.3989422804,0.1994711402); + kern[1] = vec2(0.2419707245,0.1760326634); + kern[2] = vec2(0.0539909665,0.1209853623); + kern[3] = vec2(0.0044318484,0.0647587978); return kern[i]; } @@ -102,33 +108,37 @@ void main() // perturb sampling origin slightly in screen-space to hide edge-ghosting artifacts where smoothing radius is quite large vec2 tc_v = fract(0.5 * tc.xy); // we now have floor(mod(tc,2.0))*0.5 float tc_mod = 2.0 * abs(tc_v.x - tc_v.y); // diff of x,y makes checkerboard - tc += ( (tc_mod - 0.5) * getKern(1).z * dlt * 0.5 ); + tc += ( (tc_mod - 0.5) * dlt * 0.5 ); for (int i = 1; i < 4; i++) { - vec2 samptc = (tc + getKern(i).z * dlt); - vec3 samppos = getPosition(samptc).xyz; + vec2 samptc = (tc + i * dlt); + vec3 samppos = getPosition(samptc).xyz; float d = dot(norm.xyz, samppos.xyz-pos.xyz);// dist from plane + if (d*d <= pointplanedist_tolerance_pow2) { - col += texture2DRect(lightMap, samptc)*getKern(i).xyxx; - defined_weight += getKern(i).xy; + vec4 weight = getKern(i).xyxx; + col += texture2DRect(lightMap, samptc)*weight; + defined_weight += weight.xy; } } for (int i = 1; i < 4; i++) { - vec2 samptc = (tc - getKern(i).z * dlt); - vec3 samppos = getPosition(samptc).xyz; + vec2 samptc = (tc - i * dlt); + vec3 samppos = getPosition(samptc).xyz; float d = dot(norm.xyz, samppos.xyz-pos.xyz);// dist from plane + if (d*d <= pointplanedist_tolerance_pow2) { - col += texture2DRect(lightMap, samptc)*getKern(i).xyxx; - defined_weight += getKern(i).xy; + vec4 weight = getKern(i).xyxx; + col += texture2DRect(lightMap, samptc)*weight; + defined_weight += weight.xy; } } col /= defined_weight.xyxx; - col.y *= col.y; // delinearize SSAO effect post-blur + //col.y *= col.y; // delinearize SSAO effect post-blur // Singu note: Performed pre-blur as to remove blur requirement frag_color = col; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/downsampleDepthNearestF.glsl b/indra/newview/app_settings/shaders/class1/deferred/downsampleDepthNearestF.glsl new file mode 100644 index 000000000..9b6355fb9 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/downsampleDepthNearestF.glsl @@ -0,0 +1,41 @@ +/** + * @file sunLightF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +//#extension GL_ARB_texture_rectangle : enable + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +uniform sampler2DRect depthMap; + +VARYING vec2 vary_fragcoord; + +void main() +{ + gl_FragDepth = texture2DRect(depthMap, vary_fragcoord.xy).r; +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl b/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl index a1ae08bb6..a0e1af439 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl @@ -31,120 +31,19 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif -//class 1 -- no shadow, SSAO only - -uniform sampler2DRect depthMap; -uniform sampler2DRect normalMap; -uniform sampler2D noiseMap; - - -// Inputs -uniform float ssao_radius; -uniform float ssao_max_radius; -uniform float ssao_factor; -uniform float ssao_factor_inv; - VARYING vec2 vary_fragcoord; -uniform mat4 inv_proj; +uniform sampler2DRect depthMapDownsampled; +uniform sampler2DRect depthMap; + +uniform sampler2DRect diffuseRect; +uniform float downsampled_depth_scale; uniform vec2 screen_res; -vec2 encode_normal(vec3 n) -{ - float f = sqrt(8 * n.z + 8); - return n.xy / f + 0.5; -} - -vec3 decode_normal (vec2 enc) -{ - vec2 fenc = enc*4-2; - float f = dot(fenc,fenc); - float g = sqrt(1-f/4); - vec3 n; - n.xy = fenc*g; - n.z = 1-f/2; - return n; -} - -vec4 getPosition(vec2 pos_screen) -{ - float depth = texture2DRect(depthMap, pos_screen.xy).r; - vec2 sc = pos_screen.xy*2.0; - sc /= screen_res; - sc -= vec2(1.0,1.0); - vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); - vec4 pos = inv_proj * ndc; - pos /= pos.w; - pos.w = 1.0; - return pos; -} - -//calculate decreases in ambient lighting when crowded out (SSAO) -float calcAmbientOcclusion(vec4 pos, vec3 norm) -{ - vec2 kern[8]; - // exponentially (^2) distant occlusion samples spread around origin - kern[0] = vec2(-1.0, 0.0) * 0.125*0.125; - kern[1] = vec2(1.0, 0.0) * 0.250*0.250; - kern[2] = vec2(0.0, 1.0) * 0.375*0.375; - kern[3] = vec2(0.0, -1.0) * 0.500*0.500; - kern[4] = vec2(0.7071, 0.7071) * 0.625*0.625; - kern[5] = vec2(-0.7071, -0.7071) * 0.750*0.750; - kern[6] = vec2(-0.7071, 0.7071) * 0.875*0.875; - kern[7] = vec2(0.7071, -0.7071) * 1.000*1.000; - - vec2 pos_screen = vary_fragcoord.xy; - vec3 pos_world = pos.xyz; - vec2 noise_reflect = texture2D(noiseMap, vary_fragcoord.xy/128.0).xy; - - // We treat the first sample as the origin, which definitely doesn't obscure itself thanks to being visible for sampling in the first place. - float points = 1.0; - float angle_hidden = 0.0; - - // use a kernel scale that diminishes with distance. - // a scale of less than 32 is just wasting good samples, though. - float scale = max(32.0, min(ssao_radius / -pos.z, ssao_max_radius)); - - // it was found that keeping # of samples a constant was the fastest, probably due to compiler optimizations (unrolling?) - for (int i = 0; i < 8; i++) - { - vec2 samppos_screen = pos_screen + scale * reflect(kern[i], noise_reflect); - vec3 samppos_world = getPosition(samppos_screen).xyz; - - vec3 diff = samppos_world - pos.xyz; - - if (diff.z < ssao_factor && diff.z != 0.0) - { - float dist = length(diff); - float angrel = max(0.0, dot(norm.xyz, diff/dist)); - float distrel = 1.0/(1.0+dist*dist); - float samplehidden = min(angrel, distrel); - - angle_hidden += (samplehidden); - points += 1.0; - } - } - - angle_hidden /= points; - - float rtn = (1.0 - angle_hidden); - - return (rtn * rtn); -} - void main() -{ - vec2 pos_screen = vary_fragcoord.xy; - - //try doing an unproject here - - vec4 pos = getPosition(pos_screen); - - vec3 norm = texture2DRect(normalMap, pos_screen).xyz; - norm = decode_normal(norm.xy); - +{ frag_color[0] = 1.0; - frag_color[1] = calcAmbientOcclusion(pos, norm); - frag_color[2] = 1.0; + frag_color[1] = texture2DRect(diffuseRect,vary_fragcoord.xy*downsampled_depth_scale).r; + frag_color[2] = 1.0; frag_color[3] = 1.0; } diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl index 2be812200..9b3b9ed5a 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl @@ -32,6 +32,7 @@ out vec4 frag_color; //class 2 -- shadows and SSAO +uniform sampler2DRect diffuseRect; uniform sampler2DRect depthMap; uniform sampler2DRect normalMap; uniform sampler2DShadow shadowMap0; @@ -40,16 +41,12 @@ uniform sampler2DShadow shadowMap2; uniform sampler2DShadow shadowMap3; uniform sampler2DShadow shadowMap4; uniform sampler2DShadow shadowMap5; -uniform sampler2D noiseMap; +//uniform sampler2D noiseMap; // Inputs uniform mat4 shadow_matrix[6]; uniform vec4 shadow_clip; -uniform float ssao_radius; -uniform float ssao_max_radius; -uniform float ssao_factor; -uniform float ssao_factor_inv; VARYING vec2 vary_fragcoord; @@ -66,6 +63,8 @@ uniform float shadow_offset; uniform float spot_shadow_bias; uniform float spot_shadow_offset; +uniform float downsampled_depth_scale; + vec2 encode_normal(vec3 n) { float f = sqrt(8 * n.z + 8); @@ -96,61 +95,6 @@ vec4 getPosition(vec2 pos_screen) return pos; } -vec2 getKern(int i) -{ - vec2 kern[8]; - // exponentially (^2) distant occlusion samples spread around origin - kern[0] = vec2(-1.0, 0.0) * 0.125*0.125; - kern[1] = vec2(1.0, 0.0) * 0.250*0.250; - kern[2] = vec2(0.0, 1.0) * 0.375*0.375; - kern[3] = vec2(0.0, -1.0) * 0.500*0.500; - kern[4] = vec2(0.7071, 0.7071) * 0.625*0.625; - kern[5] = vec2(-0.7071, -0.7071) * 0.750*0.750; - kern[6] = vec2(-0.7071, 0.7071) * 0.875*0.875; - kern[7] = vec2(0.7071, -0.7071) * 1.000*1.000; - - return kern[i]; -} - -//calculate decreases in ambient lighting when crowded out (SSAO) -float calcAmbientOcclusion(vec4 pos, vec3 norm) -{ - vec2 pos_screen = vary_fragcoord.xy; - vec2 noise_reflect = texture2D(noiseMap, vary_fragcoord.xy/128.0).xy; - - // We treat the first sample as the origin, which definitely doesn't obscure itself thanks to being visible for sampling in the first place. - float points = 1.0; - float angle_hidden = 0.0; - - // use a kernel scale that diminishes with distance. - // a scale of less than 32 is just wasting good samples, though. - float scale = max(32.0, min(ssao_radius / -pos.z, ssao_max_radius)); - - // it was found that keeping # of samples a constant was the fastest, probably due to compiler optimizations (unrolling?) - for (int i = 0; i < 8; i++) - { - vec2 samppos_screen = pos_screen + scale * reflect(getKern(i), noise_reflect); - vec3 samppos_world = getPosition(samppos_screen).xyz; - - vec3 diff = samppos_world - pos.xyz; - - if (diff.z < ssao_factor && diff.z != 0.0) - { - float dist = length(diff); - float angrel = max(0.0, dot(norm.xyz, diff/dist)); - float distrel = 1.0/(1.0+dist*dist); - float samplehidden = min(angrel, distrel); - - angle_hidden += (samplehidden); - points += 1.0; - } - } - - angle_hidden /= points; - float rtn = (1.0 - angle_hidden); - return (rtn * rtn); -} - float pcfShadow(sampler2DShadow shadowMap, vec4 stc, float scl, vec2 pos_screen) { stc.xyz /= stc.w; @@ -301,7 +245,7 @@ void main() } frag_color[0] = shadow; - frag_color[1] = calcAmbientOcclusion(pos, norm); + frag_color[1] = texture2DRect(diffuseRect,vary_fragcoord*downsampled_depth_scale); spos = vec4(shadow_pos+norm*spot_shadow_offset, 1.0); diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 23e407d40..c8f2d4c9a 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -693,6 +693,7 @@ void settings_setup_listeners() gSavedSettings.getControl("RenderDeferred")->getSignal()->connect(boost::bind(&handleRenderDeferredChanged, _2)); gSavedSettings.getControl("RenderShadowDetail")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); gSavedSettings.getControl("RenderDeferredSSAO")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); + gSavedSettings.getControl("SHRenderSSAOResolutionScale")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2)); gSavedSettings.getControl("RenderDepthOfField")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); gSavedSettings.getControl("RenderPerformanceTest")->getSignal()->connect(boost::bind(&handleRenderPerfTestChanged, _2)); gSavedSettings.getControl("TextureMemory")->getSignal()->connect(boost::bind(&handleVideoMemoryChanged, _2)); diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 6df2a4f28..93b4e6b5a 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -206,6 +206,8 @@ LLGLSLShader gDeferredLightProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShaderArray gDeferredMultiLightProgram[16]; LLGLSLShader gDeferredSpotLightProgram(LLViewerShaderMgr::SHADER_DEFERRED); //Not in mShaderList LLGLSLShader gDeferredMultiSpotLightProgram(LLViewerShaderMgr::SHADER_DEFERRED); //Not in mShaderList +LLGLSLShader gDeferredSSAOProgram(LLViewerShaderMgr::SHADER_DEFERRED); +LLGLSLShader gDeferredDownsampleDepthNearestProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredSunProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredBlurLightProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredSoftenProgram(LLViewerShaderMgr::SHADER_DEFERRED); @@ -1336,6 +1338,29 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() success = gDeferredSunProgram.createShader(NULL, NULL); } + if(gSavedSettings.getBOOL("RenderDeferredSSAO")) + { + if (success) + { + gDeferredSSAOProgram.mName = "Deferred Ambient Occlusion Shader"; + gDeferredSSAOProgram.mShaderFiles.clear(); + gDeferredSSAOProgram.mShaderFiles.push_back(make_pair("deferred/sunLightV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredSSAOProgram.mShaderFiles.push_back(make_pair("deferred/SSAOF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredSSAOProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + success = gDeferredSSAOProgram.createShader(NULL, NULL); + } + + if (success) + { + gDeferredDownsampleDepthNearestProgram.mName = "Deferred Nearest Downsample Depth Shader"; + gDeferredDownsampleDepthNearestProgram.mShaderFiles.clear(); + gDeferredDownsampleDepthNearestProgram.mShaderFiles.push_back(make_pair("deferred/sunLightV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredDownsampleDepthNearestProgram.mShaderFiles.push_back(make_pair("deferred/downsampleDepthNearestF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredDownsampleDepthNearestProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + success = gDeferredDownsampleDepthNearestProgram.createShader(NULL, NULL); + } + } + if (success) { gDeferredBlurLightProgram.mName = "Deferred Blur Light Shader"; diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h index 320c25828..99374c31a 100644 --- a/indra/newview/llviewershadermgr.h +++ b/indra/newview/llviewershadermgr.h @@ -313,6 +313,8 @@ extern LLGLSLShaderArray gDeferredMultiLig extern LLGLSLShader gDeferredSpotLightProgram; extern LLGLSLShader gDeferredMultiSpotLightProgram; extern LLGLSLShader gDeferredSunProgram; +extern LLGLSLShader gDeferredSSAOProgram; +extern LLGLSLShader gDeferredDownsampleDepthNearestProgram; extern LLGLSLShader gDeferredBlurLightProgram; extern LLGLSLShader gDeferredAvatarProgram; extern LLGLSLShader gDeferredSoftenProgram; diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index e6aec53bb..7d2095334 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -207,11 +207,11 @@ LLFastTimer::DeclareTimer FTM_RENDER_DEFERRED("Deferred Shading"); static LLFastTimer::DeclareTimer FTM_STATESORT_DRAWABLE("Sort Drawables"); static LLFastTimer::DeclareTimer FTM_STATESORT_POSTSORT("Post Sort"); -static LLStaticHashedString sTint("tint"); -static LLStaticHashedString sAmbiance("ambiance"); -static LLStaticHashedString sAlphaScale("alpha_scale"); +//static LLStaticHashedString sTint("tint"); +//static LLStaticHashedString sAmbiance("ambiance"); +//static LLStaticHashedString sAlphaScale("alpha_scale"); static LLStaticHashedString sNormMat("norm_mat"); -static LLStaticHashedString sOffset("offset"); +//static LLStaticHashedString sOffset("offset"); static LLStaticHashedString sScreenRes("screenRes"); static LLStaticHashedString sDelta("delta"); static LLStaticHashedString sDistFactor("dist_factor"); @@ -796,12 +796,15 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) mSampleBuffer.release(); mScreen.release(); + mDeferredDownsampledDepth.release(); + if (LLPipeline::sRenderDeferred) { - S32 shadow_detail = gSavedSettings.getS32("RenderShadowDetail"); - BOOL ssao = gSavedSettings.getBOOL("RenderDeferredSSAO"); - BOOL RenderDepthOfField = gSavedSettings.getBOOL("RenderDepthOfField"); + static const LLCachedControl shadow_detail("RenderShadowDetail",0); + static const LLCachedControl ssao ("RenderDeferredSSAO",false); + static const LLCachedControl RenderDepthOfField("RenderDepthOfField",false); static const LLCachedControl RenderShadowResolutionScale("RenderShadowResolutionScale",1.0f); + static const LLCachedControl RenderSSAOResolutionScale("SHRenderSSAOResolutionScale",.5f); const U32 occlusion_divisor = 3; @@ -835,6 +838,11 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) if (shadow_detail > 0 || ssao || RenderDepthOfField || samples > 0) { //only need mDeferredLight for shadows OR ssao OR dof OR fxaa if (!mDeferredLight.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false; + if(ssao) + { + F32 scale = llclamp(RenderSSAOResolutionScale.get(),.01f,1.f); + if( scale < 1.f && !mDeferredDownsampledDepth.allocate(llceil(F32(resX)*scale), llceil(F32(resY)*scale), 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE) ) return false; + } } else { @@ -901,6 +909,7 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) mScreen.release(); mDeferredScreen.release(); //make sure to release any render targets that share a depth buffer with mDeferredScreen first mDeferredDepth.release(); + mDeferredDownsampledDepth.release(); mOcclusionDepth.release(); if (!mScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false; @@ -1022,6 +1031,7 @@ void LLPipeline::releaseScreenBuffers() mPhysicsDisplay.release(); mDeferredScreen.release(); mDeferredDepth.release(); + mDeferredDownsampledDepth.release(); mDeferredLight.release(); mOcclusionDepth.release(); @@ -7648,6 +7658,7 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, U32 n static const LLCachedControl RenderSpotShadowBias("RenderSpotShadowBias",0.f); static const LLCachedControl RenderEdgeDepthCutoff("RenderEdgeDepthCutoff",.01f); static const LLCachedControl RenderEdgeNormCutoff("RenderEdgeNormCutoff",.25f); + static const LLCachedControl RenderSSAOResolutionScale("SHRenderSSAOResolutionScale",.5f); if (noise_map == 0xFFFFFFFF) { @@ -7677,10 +7688,21 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, U32 n gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); } + S32 channel2 = shader.enableTexture(LLShaderMgr::DEFERRED_DOWNSAMPLED_DEPTH, mDeferredDepth.getUsage()); channel = shader.enableTexture(LLShaderMgr::DEFERRED_DEPTH, mDeferredDepth.getUsage()); - if (channel > -1) + if (channel > -1 || channel2 >= -1) { - gGL.getTexUnit(channel)->bind(&mDeferredDepth, TRUE); + if(channel > -1) + gGL.getTexUnit(channel)->bind(&mDeferredDepth, TRUE); + if(channel2 > -1) + { + F32 scale = llclamp(RenderSSAOResolutionScale.get(),.01f,1.f); + if(scale < 1.f) + gGL.getTexUnit(channel2)->bind(&mDeferredDownsampledDepth, TRUE); + else + gGL.getTexUnit(channel2)->bind(&mDeferredDepth, TRUE); //Bind full res depth instead, as downsampling is disabled if scale == 1.f + } + //gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); stop_glerror(); @@ -7774,21 +7796,24 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, U32 n stop_glerror(); - F32 mat[16*6]; - for (U32 i = 0; i < 16; i++) + if(shader.getUniformLocation(LLShaderMgr::DEFERRED_SHADOW_MATRIX) >= 0) { - mat[i] = mSunShadowMatrix[0].m[i]; - mat[i+16] = mSunShadowMatrix[1].m[i]; - mat[i+32] = mSunShadowMatrix[2].m[i]; - mat[i+48] = mSunShadowMatrix[3].m[i]; - mat[i+64] = mSunShadowMatrix[4].m[i]; - mat[i+80] = mSunShadowMatrix[5].m[i]; + F32 mat[16*6]; + for (U32 i = 0; i < 16; i++) + { + mat[i] = mSunShadowMatrix[0].m[i]; + mat[i+16] = mSunShadowMatrix[1].m[i]; + mat[i+32] = mSunShadowMatrix[2].m[i]; + mat[i+48] = mSunShadowMatrix[3].m[i]; + mat[i+64] = mSunShadowMatrix[4].m[i]; + mat[i+80] = mSunShadowMatrix[5].m[i]; + } + + shader.uniformMatrix4fv(LLShaderMgr::DEFERRED_SHADOW_MATRIX, 6, FALSE, mat); + + stop_glerror(); } - shader.uniformMatrix4fv(LLShaderMgr::DEFERRED_SHADOW_MATRIX, 6, FALSE, mat); - - stop_glerror(); - channel = shader.enableTexture(LLShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); if (channel > -1) { @@ -7844,6 +7869,8 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, U32 n glh::matrix4f norm_mat = glh_get_current_modelview().inverse().transpose(); shader.uniformMatrix4fv(LLShaderMgr::DEFERRED_NORM_MATRIX, 1, FALSE, norm_mat.m); } + + shader.uniform1f(LLShaderMgr::DEFERRED_DOWNSAMPLED_DEPTH_SCALE, llclamp(RenderSSAOResolutionScale.get(),.01f,1.f)); } static LLFastTimer::DeclareTimer FTM_GI_TRACE("Trace"); @@ -7867,6 +7894,7 @@ void LLPipeline::renderDeferredLighting() static const LLCachedControl RenderFSAASamples("RenderFSAASamples",0); static const LLCachedControl RenderDeferredSSAO("RenderDeferredSSAO",false); + static const LLCachedControl RenderSSAOResolutionScale("SHRenderSSAOResolutionScale",.5f); static const LLCachedControl RenderShadowDetail("RenderShadowDetail",0); static const LLCachedControl RenderShadowGaussian("RenderShadowGaussian",LLVector3(3.f,2.f,0.f)); static const LLCachedControl RenderShadowBlurSize("RenderShadowBlurSize",1.4f); @@ -7933,6 +7961,54 @@ void LLPipeline::renderDeferredLighting() gGL.pushMatrix(); gGL.loadIdentity(); + if (RenderDeferredSSAO) + { + F32 ssao_scale = llclamp(RenderSSAOResolutionScale.get(),.01f,1.f); + + LLGLDisable blend(GL_BLEND); + + //Downsample with fullscreen quad. GL_NEAREST + if(ssao_scale < 1.f) + { + mDeferredDownsampledDepth.bindTarget(); + mDeferredDownsampledDepth.clear(GL_DEPTH_BUFFER_BIT); + bindDeferredShader(gDeferredDownsampleDepthNearestProgram, 0); + gDeferredDownsampleDepthNearestProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, mDeferredDownsampledDepth.getWidth()/ssao_scale, mDeferredDownsampledDepth.getHeight()/ssao_scale); + mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + { + LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS); + stop_glerror(); + mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); + stop_glerror(); + } + mDeferredDownsampledDepth.flush(); + unbindDeferredShader(gDeferredDownsampleDepthNearestProgram); + } + + //Run SSAO + { + mScreen.bindTarget(); + glClearColor(1,1,1,1); + mScreen.clear(GL_COLOR_BUFFER_BIT); + glClearColor(0,0,0,0); + bindDeferredShader(gDeferredSSAOProgram, 0); + if(ssao_scale < 1.f) + { + glViewport(0,0,mDeferredDownsampledDepth.getWidth(),mDeferredDownsampledDepth.getHeight()); + gDeferredSSAOProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, mDeferredDownsampledDepth.getWidth()/ssao_scale, mDeferredDownsampledDepth.getHeight()/ssao_scale); + } + mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + { + LLGLDepthTest depth(GL_FALSE); + stop_glerror(); + mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); + stop_glerror(); + } + mScreen.flush(); + unbindDeferredShader(gDeferredSSAOProgram); + } + } + if (RenderDeferredSSAO || RenderShadowDetail > 0) { mDeferredLight.bindTarget(); @@ -7944,7 +8020,7 @@ void LLPipeline::renderDeferredLighting() mDeferredLight.clear(GL_COLOR_BUFFER_BIT); glClearColor(0,0,0,0); - glh::matrix4f inv_trans = glh_get_current_modelview().inverse().transpose(); + /*glh::matrix4f inv_trans = glh_get_current_modelview().inverse().transpose(); const U32 slice = 32; F32 offset[slice*3]; @@ -7978,8 +8054,18 @@ void LLPipeline::renderDeferredLighting() } } - gDeferredSunProgram.uniform3fv(sOffset, slice, offset); + gDeferredSunProgram.uniform3fv(sOffset, slice, offset);*/ + gDeferredSunProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, mDeferredLight.getWidth(), mDeferredLight.getHeight()); + + //Enable bilinear filtering, as the screen tex resolution may not match current framebuffer resolution. Eg, half-res SSAO + // diffuse map should only be found if the sun shader is the SSAO variant. + S32 channel = gDeferredSunProgram.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage()); + if (channel > -1) + { + mScreen.bindTexture(0,channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + } { LLGLDisable blend(GL_BLEND); @@ -7988,6 +8074,11 @@ void LLPipeline::renderDeferredLighting() mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); stop_glerror(); } + + if (channel > -1) + { + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } unbindDeferredShader(gDeferredSunProgram); } @@ -8106,6 +8197,9 @@ void LLPipeline::renderDeferredLighting() gPipeline.pushRenderTypeMask(); gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY, +#if ENABLE_CLASSIC_CLOUDS + LLPipeline::RENDER_TYPE_CLASSIC_CLOUDS, +#endif LLPipeline::RENDER_TYPE_WL_CLOUDS, LLPipeline::RENDER_TYPE_WL_SKY, LLPipeline::END_RENDER_TYPES); @@ -8500,6 +8594,7 @@ void LLPipeline::renderDeferredLightingToRT(LLRenderTarget* target) static const LLCachedControl RenderFSAASamples("RenderFSAASamples",0); static const LLCachedControl RenderDeferredSSAO("RenderDeferredSSAO",false); + static const LLCachedControl RenderSSAOResolutionScale("SHRenderSSAOResolutionScale",.5f); static const LLCachedControl RenderShadowDetail("RenderShadowDetail",0); static const LLCachedControl RenderShadowGaussian("RenderShadowGaussian",LLVector3(3.f,2.f,0.f)); static const LLCachedControl RenderShadowBlurSize("RenderShadowBlurSize",1.4f); @@ -8560,6 +8655,54 @@ void LLPipeline::renderDeferredLightingToRT(LLRenderTarget* target) gGL.pushMatrix(); gGL.loadIdentity(); + if (RenderDeferredSSAO) + { + F32 ssao_scale = llclamp(RenderSSAOResolutionScale.get(),.01f,1.f); + + LLGLDisable blend(GL_BLEND); + + //Downsample with fullscreen quad. GL_NEAREST + if(ssao_scale < 1.f) + { + mDeferredDownsampledDepth.bindTarget(); + mDeferredDownsampledDepth.clear(GL_DEPTH_BUFFER_BIT); + bindDeferredShader(gDeferredDownsampleDepthNearestProgram, 0); + gDeferredDownsampleDepthNearestProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, mDeferredDownsampledDepth.getWidth()/ssao_scale, mDeferredDownsampledDepth.getHeight()/ssao_scale); + mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + { + LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS); + stop_glerror(); + mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); + stop_glerror(); + } + mDeferredDownsampledDepth.flush(); + unbindDeferredShader(gDeferredDownsampleDepthNearestProgram); + } + + //Run SSAO + { + mScreen.bindTarget(); + glClearColor(1,1,1,1); + mScreen.clear(GL_COLOR_BUFFER_BIT); + glClearColor(0,0,0,0); + bindDeferredShader(gDeferredSSAOProgram, 0); + if(ssao_scale < 1.f) + { + glViewport(0,0,mDeferredDownsampledDepth.getWidth(),mDeferredDownsampledDepth.getHeight()); + gDeferredSSAOProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, mDeferredDownsampledDepth.getWidth()/ssao_scale, mDeferredDownsampledDepth.getHeight()/ssao_scale); + } + mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + { + LLGLDepthTest depth(GL_FALSE); + stop_glerror(); + mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); + stop_glerror(); + } + mScreen.flush(); + unbindDeferredShader(gDeferredSSAOProgram); + } + } + if (RenderDeferredSSAO || RenderShadowDetail > 0) { mDeferredLight.bindTarget(); @@ -8571,7 +8714,7 @@ void LLPipeline::renderDeferredLightingToRT(LLRenderTarget* target) mDeferredLight.clear(GL_COLOR_BUFFER_BIT); glClearColor(0,0,0,0); - glh::matrix4f inv_trans = glh_get_current_modelview().inverse().transpose(); + /*glh::matrix4f inv_trans = glh_get_current_modelview().inverse().transpose(); const U32 slice = 32; F32 offset[slice*3]; @@ -8590,9 +8733,18 @@ void LLPipeline::renderDeferredLightingToRT(LLRenderTarget* target) } } - gDeferredSunProgram.uniform3fv(LLShaderMgr::DEFERRED_SHADOW_OFFSET, slice, offset); + gDeferredSunProgram.uniform3fv(LLShaderMgr::DEFERRED_SHADOW_OFFSET, slice, offset);*/ gDeferredSunProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, mDeferredLight.getWidth(), mDeferredLight.getHeight()); + //Enable bilinear filtering, as the screen tex resolution may not match current framebuffer resolution. Eg, half-res SSAO + // diffuse map should only be found if the sun shader is the SSAO variant. + S32 channel = gDeferredSunProgram.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage()); + if (channel > -1) + { + mScreen.bindTexture(0,channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + } + { LLGLDisable blend(GL_BLEND); LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); @@ -8600,6 +8752,11 @@ void LLPipeline::renderDeferredLightingToRT(LLRenderTarget* target) mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); stop_glerror(); } + + if (channel > -1) + { + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } unbindDeferredShader(gDeferredSunProgram); } @@ -8656,7 +8813,10 @@ void LLPipeline::renderDeferredLightingToRT(LLRenderTarget* target) gPipeline.pushRenderTypeMask(); gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY, +#if ENABLE_CLASSIC_CLOUDS LLPipeline::RENDER_TYPE_CLASSIC_CLOUDS, +#endif + LLPipeline::RENDER_TYPE_WL_CLOUDS, LLPipeline::RENDER_TYPE_WL_SKY, LLPipeline::END_RENDER_TYPES); diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 453512d80..6a7d7479d 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -615,6 +615,7 @@ public: LLRenderTarget mFXAABuffer; LLRenderTarget mEdgeMap; LLRenderTarget mDeferredDepth; + LLRenderTarget mDeferredDownsampledDepth; LLRenderTarget mOcclusionDepth; LLRenderTarget mDeferredLight; LLMultisampleBuffer mSampleBuffer;