зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1604615 - Use optimized shader source in webrender. r=jrmuizel
Add a gecko pref "gfx.webrender.use-optimized-shaders". If enabled, then when attempting to compile a webrender shader first look for the optimized source. If the optimized source is not present, emit a warning and fall back to the unoptimized source. Use the optimized source by default in wrench, and add the flag "--use-unoptimized-shaders" to override this. Differential Revision: https://phabricator.services.mozilla.com/D70033
This commit is contained in:
Родитель
f548e9a284
Коммит
d9a1b3bbde
|
@ -45,6 +45,7 @@ class gfxVarReceiver;
|
|||
_(UseWebRenderTripleBufferingWin, bool, false) \
|
||||
_(UseWebRenderCompositor, bool, false) \
|
||||
_(UseWebRenderProgramBinaryDisk, bool, false) \
|
||||
_(UseWebRenderOptimizedShaders, bool, false) \
|
||||
_(UseWebRenderMultithreading, bool, false) \
|
||||
_(WebRenderMaxPartialPresentRects, int32_t, 0) \
|
||||
_(WebRenderDebugFlags, int32_t, 0) \
|
||||
|
|
|
@ -125,6 +125,10 @@ const char* gfx_wr_resource_path_override() {
|
|||
return resourcePath;
|
||||
}
|
||||
|
||||
bool gfx_wr_use_optimized_shaders() {
|
||||
return mozilla::gfx::gfxVars::UseWebRenderOptimizedShaders();
|
||||
}
|
||||
|
||||
void gfx_critical_note(const char* msg) { gfxCriticalNote << msg; }
|
||||
|
||||
void gfx_critical_error(const char* msg) { gfxCriticalError() << msg; }
|
||||
|
|
|
@ -3032,6 +3032,10 @@ void gfxPlatform::InitWebRenderConfig() {
|
|||
gfxConfig::IsEnabled(Feature::WEBRENDER));
|
||||
}
|
||||
|
||||
if (StaticPrefs::gfx_webrender_use_optimized_shaders_AtStartup()) {
|
||||
gfxVars::SetUseWebRenderOptimizedShaders(gfxConfig::IsEnabled(Feature::WEBRENDER));
|
||||
}
|
||||
|
||||
if (Preferences::GetBool("gfx.webrender.software", false)) {
|
||||
gfxVars::SetUseSoftwareWebRender(gfxConfig::IsEnabled(Feature::WEBRENDER));
|
||||
}
|
||||
|
|
|
@ -510,6 +510,7 @@ extern "C" {
|
|||
// by commenting out the path that adds an external image ID
|
||||
fn gfx_use_wrench() -> bool;
|
||||
fn gfx_wr_resource_path_override() -> *const c_char;
|
||||
fn gfx_wr_use_optimized_shaders() -> bool;
|
||||
// TODO: make gfx_critical_error() work.
|
||||
// We still have problem to pass the error message from render/render_backend
|
||||
// thread to main thread now.
|
||||
|
@ -1142,6 +1143,8 @@ fn wr_device_new(gl_context: *mut c_void, pc: Option<&mut WrProgramCache>) -> De
|
|||
}
|
||||
};
|
||||
|
||||
let use_optimized_shaders = unsafe { gfx_wr_use_optimized_shaders() };
|
||||
|
||||
let cached_programs = match pc {
|
||||
Some(cached_programs) => Some(Rc::clone(cached_programs.rc_get())),
|
||||
None => None,
|
||||
|
@ -1150,6 +1153,7 @@ fn wr_device_new(gl_context: *mut c_void, pc: Option<&mut WrProgramCache>) -> De
|
|||
Device::new(
|
||||
gl,
|
||||
resource_override_path,
|
||||
use_optimized_shaders,
|
||||
upload_method,
|
||||
cached_programs,
|
||||
false,
|
||||
|
@ -1427,6 +1431,7 @@ pub extern "C" fn wr_window_new(
|
|||
}
|
||||
}
|
||||
},
|
||||
use_optimized_shaders: unsafe { gfx_wr_use_optimized_shaders() },
|
||||
renderer_id: Some(window_id.0),
|
||||
upload_method,
|
||||
scene_builder_hooks: Some(Box::new(APZCallbacks::new(window_id))),
|
||||
|
|
|
@ -23,6 +23,7 @@ bool is_glcontext_gles(void* glcontext_ptr);
|
|||
bool is_glcontext_angle(void* glcontext_ptr);
|
||||
bool gfx_use_wrench();
|
||||
const char* gfx_wr_resource_path_override();
|
||||
bool gfx_wr_use_optimized_shaders();
|
||||
void gfx_critical_note(const char* msg);
|
||||
void gfx_critical_error(const char* msg);
|
||||
void gecko_printf_stderr_output(const char* msg);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use super::super::shader_source::UNOPTIMIZED_SHADERS;
|
||||
use super::super::shader_source::{OPTIMIZED_SHADERS, UNOPTIMIZED_SHADERS};
|
||||
use api::{ColorF, ImageDescriptor, ImageFormat, MemoryReport};
|
||||
use api::{MixBlendMode, TextureTarget, VoidPtrToSizeFn};
|
||||
use api::units::*;
|
||||
|
@ -662,10 +662,17 @@ pub struct VBOId(gl::GLuint);
|
|||
#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
|
||||
struct IBOId(gl::GLuint);
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
enum ProgramSourceType {
|
||||
Unoptimized,
|
||||
Optimized(ShaderVersion),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ProgramSourceInfo {
|
||||
base_filename: &'static str,
|
||||
features: Vec<&'static str>,
|
||||
source_type: ProgramSourceType,
|
||||
digest: ProgramSourceDigest,
|
||||
}
|
||||
|
||||
|
@ -677,32 +684,63 @@ impl ProgramSourceInfo {
|
|||
) -> Self {
|
||||
|
||||
// Compute the digest. Assuming the device has a `ProgramCache`, this
|
||||
// will always be needed, whereas the source is rarely needed. As such,
|
||||
// we compute the hash by walking the static strings in the same order
|
||||
// as we would when concatenating the source, to avoid heap-allocating
|
||||
// in the common case.
|
||||
//
|
||||
// Note that we cheat a bit to make the hashing more efficient. First,
|
||||
// the only difference between the vertex and fragment shader is a
|
||||
// single deterministic define, so we don't need to hash both. Second,
|
||||
// we precompute the digest of the expanded source file at build time,
|
||||
// and then just hash that digest here.
|
||||
// will always be needed, whereas the source is rarely needed.
|
||||
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::hash::Hasher;
|
||||
|
||||
// Setup.
|
||||
let mut hasher = DefaultHasher::new();
|
||||
let version = get_shader_version(&*device.gl());
|
||||
let override_path = device.resource_override_path.as_ref();
|
||||
let source_and_digest = UNOPTIMIZED_SHADERS.get(&name).expect("Shader not found");
|
||||
let gl_version = get_shader_version(&*device.gl());
|
||||
|
||||
// Hash the renderer name.
|
||||
hasher.write(device.capabilities.renderer_name.as_bytes());
|
||||
|
||||
let full_name = &Self::full_name(name, features);
|
||||
|
||||
let optimized_source = if device.use_optimized_shaders {
|
||||
OPTIMIZED_SHADERS.get(&(gl_version, full_name)).or_else(|| {
|
||||
warn!("Missing optimized shader source for {}", full_name);
|
||||
None
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let source_type = match optimized_source {
|
||||
Some(source_and_digest) => {
|
||||
// Optimized shader sources are used as-is, without any run-time processing.
|
||||
// The vertex and fragment shaders are different, so must both be hashed.
|
||||
// We use the hashes that were computed at build time, and verify it in debug builds.
|
||||
if cfg!(debug_assertions) {
|
||||
let mut h = DefaultHasher::new();
|
||||
h.write(source_and_digest.vert_source.as_bytes());
|
||||
h.write(source_and_digest.frag_source.as_bytes());
|
||||
let d: ProgramSourceDigest = h.into();
|
||||
let digest = d.to_string();
|
||||
debug_assert_eq!(digest, source_and_digest.digest);
|
||||
hasher.write(digest.as_bytes());
|
||||
} else {
|
||||
hasher.write(source_and_digest.digest.as_bytes());
|
||||
}
|
||||
|
||||
ProgramSourceType::Optimized(gl_version)
|
||||
}
|
||||
None => {
|
||||
// For non-optimized sources we compute the hash by walking the static strings
|
||||
// in the same order as we would when concatenating the source, to avoid
|
||||
// heap-allocating in the common case.
|
||||
//
|
||||
// Note that we cheat a bit to make the hashing more efficient. First, the only
|
||||
// difference between the vertex and fragment shader is a single deterministic
|
||||
// define, so we don't need to hash both. Second, we precompute the digest of the
|
||||
// expanded source file at build time, and then just hash that digest here.
|
||||
let override_path = device.resource_override_path.as_ref();
|
||||
let source_and_digest = UNOPTIMIZED_SHADERS.get(&name).expect("Shader not found");
|
||||
|
||||
// Hash the prefix string.
|
||||
build_shader_prefix_string(
|
||||
version,
|
||||
gl_version,
|
||||
&features,
|
||||
ShaderKind::Vertex,
|
||||
&name,
|
||||
|
@ -724,17 +762,35 @@ impl ProgramSourceInfo {
|
|||
hasher.write(digest.as_bytes());
|
||||
} else {
|
||||
hasher.write(source_and_digest.digest.as_bytes());
|
||||
}
|
||||
|
||||
ProgramSourceType::Unoptimized
|
||||
}
|
||||
};
|
||||
|
||||
// Finish.
|
||||
ProgramSourceInfo {
|
||||
base_filename: name,
|
||||
features: features.to_vec(),
|
||||
source_type,
|
||||
digest: hasher.into(),
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_source(&self, device: &Device, kind: ShaderKind) -> String {
|
||||
let full_name = Self::full_name(self.base_filename, &self.features);
|
||||
match self.source_type {
|
||||
ProgramSourceType::Optimized(gl_version) => {
|
||||
let shader = OPTIMIZED_SHADERS
|
||||
.get(&(gl_version, &full_name))
|
||||
.unwrap_or_else(|| panic!("Missing optimized shader source for {}", full_name));
|
||||
|
||||
match kind {
|
||||
ShaderKind::Vertex => shader.vert_source.to_string(),
|
||||
ShaderKind::Fragment => shader.frag_source.to_string(),
|
||||
}
|
||||
},
|
||||
ProgramSourceType::Unoptimized => {
|
||||
let mut src = String::new();
|
||||
device.build_shader_string(
|
||||
&self.features,
|
||||
|
@ -744,6 +800,16 @@ impl ProgramSourceInfo {
|
|||
);
|
||||
src
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn full_name(base_filename: &'static str, features: &[&'static str]) -> String {
|
||||
if features.is_empty() {
|
||||
base_filename.to_string()
|
||||
} else {
|
||||
format!("{}_{}", base_filename, features.join("_"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "serialize_program", derive(Deserialize, Serialize))]
|
||||
|
@ -1015,6 +1081,9 @@ pub struct Device {
|
|||
// resources
|
||||
resource_override_path: Option<PathBuf>,
|
||||
|
||||
/// Whether to use shaders that have been optimized at build time.
|
||||
use_optimized_shaders: bool,
|
||||
|
||||
max_texture_size: i32,
|
||||
max_texture_layers: u32,
|
||||
cached_programs: Option<Rc<ProgramCache>>,
|
||||
|
@ -1250,6 +1319,7 @@ impl Device {
|
|||
pub fn new(
|
||||
mut gl: Rc<dyn gl::Gl>,
|
||||
resource_override_path: Option<PathBuf>,
|
||||
use_optimized_shaders: bool,
|
||||
upload_method: UploadMethod,
|
||||
cached_programs: Option<Rc<ProgramCache>>,
|
||||
allow_pixel_local_storage_support: bool,
|
||||
|
@ -1408,7 +1478,8 @@ impl Device {
|
|||
),
|
||||
};
|
||||
|
||||
let (depth_format, upload_method) = if renderer_name.starts_with("Software WebRender") {
|
||||
let is_software_webrender = renderer_name.starts_with("Software WebRender");
|
||||
let (depth_format, upload_method) = if is_software_webrender {
|
||||
(gl::DEPTH_COMPONENT16, UploadMethod::Immediate)
|
||||
} else {
|
||||
(gl::DEPTH_COMPONENT24, upload_method)
|
||||
|
@ -1449,6 +1520,9 @@ impl Device {
|
|||
gl::GlType::Gles => supports_extension(&extensions,"GL_EXT_blend_func_extended"),
|
||||
};
|
||||
|
||||
// Software webrender relies on the unoptimized shader source.
|
||||
let use_optimized_shaders = use_optimized_shaders && !is_software_webrender;
|
||||
|
||||
// On the android emulator, glShaderSource can crash if the source
|
||||
// strings are not null-terminated. See bug 1591945.
|
||||
let requires_null_terminated_shader_source = is_emulator;
|
||||
|
@ -1479,6 +1553,7 @@ impl Device {
|
|||
gl,
|
||||
base_gl: None,
|
||||
resource_override_path,
|
||||
use_optimized_shaders,
|
||||
upload_method,
|
||||
inside_frame: false,
|
||||
|
||||
|
|
|
@ -2192,6 +2192,7 @@ impl Renderer {
|
|||
let mut device = Device::new(
|
||||
gl,
|
||||
options.resource_override_path.clone(),
|
||||
options.use_optimized_shaders,
|
||||
options.upload_method.clone(),
|
||||
options.cached_programs.take(),
|
||||
options.allow_pixel_local_storage_support,
|
||||
|
@ -6713,6 +6714,8 @@ bitflags! {
|
|||
pub struct RendererOptions {
|
||||
pub device_pixel_ratio: f32,
|
||||
pub resource_override_path: Option<PathBuf>,
|
||||
/// Whether to use shaders that have been optimized at build time.
|
||||
pub use_optimized_shaders: bool,
|
||||
pub enable_aa: bool,
|
||||
pub enable_dithering: bool,
|
||||
pub max_recorded_profiles: usize,
|
||||
|
@ -6783,6 +6786,7 @@ impl Default for RendererOptions {
|
|||
RendererOptions {
|
||||
device_pixel_ratio: 1.0,
|
||||
resource_override_path: None,
|
||||
use_optimized_shaders: false,
|
||||
enable_aa: true,
|
||||
enable_dithering: false,
|
||||
debug_flags: DebugFlags::empty(),
|
||||
|
|
|
@ -21,6 +21,9 @@ args:
|
|||
long: shaders
|
||||
help: Override path for shaders
|
||||
takes_value: true
|
||||
- use_unoptimized_shaders:
|
||||
long: use-unoptimized-shaders
|
||||
help: Use unoptimized shaders rather than the shaders optimized at build-time
|
||||
- rebuild:
|
||||
short: r
|
||||
long: rebuild
|
||||
|
|
|
@ -657,6 +657,7 @@ fn main() {
|
|||
&mut window,
|
||||
events_loop.as_mut().map(|el| el.create_proxy()),
|
||||
res_path,
|
||||
!args.is_present("use_unoptimized_shaders"),
|
||||
dp_ratio,
|
||||
save_type,
|
||||
dim,
|
||||
|
|
|
@ -232,6 +232,7 @@ impl Wrench {
|
|||
window: &mut WindowWrapper,
|
||||
proxy: Option<EventsLoopProxy>,
|
||||
shader_override_path: Option<PathBuf>,
|
||||
use_optimized_shaders: bool,
|
||||
dp_ratio: f32,
|
||||
save_type: Option<SaveType>,
|
||||
size: DeviceIntSize,
|
||||
|
@ -274,6 +275,7 @@ impl Wrench {
|
|||
let opts = webrender::RendererOptions {
|
||||
device_pixel_ratio: dp_ratio,
|
||||
resource_override_path: shader_override_path,
|
||||
use_optimized_shaders,
|
||||
recorder,
|
||||
enable_subpixel_aa: !no_subpixel_aa,
|
||||
debug_flags,
|
||||
|
|
|
@ -4151,6 +4151,11 @@
|
|||
value: @IS_NIGHTLY_BUILD@
|
||||
mirror: once
|
||||
|
||||
- name: gfx.webrender.use-optimized-shaders
|
||||
type: bool
|
||||
value: true
|
||||
mirror: once
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
# Keep this pref hidden on non-nightly builds to avoid people accidentally
|
||||
# turning it on.
|
||||
|
|
Загрузка…
Ссылка в новой задаче