author | Bobby Holley <bobbyholley@gmail.com> |
Tue, 05 Mar 2019 11:31:49 -0800 | |
changeset 463222 | 1972b883694851e31344e1eefff9ac5b95d2b88c |
parent 463221 | 8426cec31aaee1ebf3b08d7287ad54f9bf4f6d97 |
child 463277 | 0537da28038acb2e22e683f6b487c8eef1db400a |
push id | 112368 |
push user | bholley@mozilla.com |
push date | Fri, 08 Mar 2019 21:35:07 +0000 |
treeherder | mozilla-inbound@1972b8836948 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | gw |
bugs | 1532810 |
milestone | 67.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp +++ b/gfx/layers/wr/WebRenderBridgeParent.cpp @@ -10,16 +10,17 @@ #include "gfxEnv.h" #include "gfxPrefs.h" #include "gfxEnv.h" #include "GeckoProfiler.h" #include "GLContext.h" #include "GLContextProvider.h" #include "nsExceptionHandler.h" #include "mozilla/Range.h" +#include "mozilla/UniquePtr.h" #include "mozilla/layers/AnimationHelper.h" #include "mozilla/layers/APZSampler.h" #include "mozilla/layers/APZUpdater.h" #include "mozilla/layers/Compositor.h" #include "mozilla/layers/CompositorBridgeParent.h" #include "mozilla/layers/CompositorThread.h" #include "mozilla/layers/CompositorVsyncScheduler.h" #include "mozilla/layers/ImageBridgeParent.h" @@ -59,16 +60,35 @@ void gecko_profiler_start_marker(const c void gecko_profiler_end_marker(const char* name) { #ifdef MOZ_GECKO_PROFILER profiler_tracing("WebRender", name, JS::ProfilingCategoryPair::GRAPHICS, TRACING_INTERVAL_END); #endif } +void gecko_profiler_add_text_marker(const char* name, const char* text_bytes, size_t text_len, uint64_t microseconds) { +#ifdef MOZ_GECKO_PROFILER + if (profiler_thread_is_being_profiled()) { + auto now = mozilla::TimeStamp::Now(); + auto start = now - mozilla::TimeDuration::FromMicroseconds(microseconds); + profiler_add_text_marker( + name, nsDependentCString(text_bytes, text_len), JS::ProfilingCategoryPair::GRAPHICS, start, now); + } +#endif +} + +bool gecko_profiler_thread_is_being_profiled() { +#ifdef MOZ_GECKO_PROFILER + return profiler_thread_is_being_profiled(); +#else + return false; +#endif +} + bool is_glcontext_egl(void* glcontext_ptr) { MOZ_ASSERT(glcontext_ptr); mozilla::gl::GLContext* glcontext = reinterpret_cast<mozilla::gl::GLContext*>(glcontext_ptr); if (!glcontext) { return false; }
--- a/gfx/webrender_bindings/src/bindings.rs +++ b/gfx/webrender_bindings/src/bindings.rs @@ -11,16 +11,17 @@ use std::path::PathBuf; use std::rc::Rc; use std::cell::RefCell; use std::sync::Arc; use std::sync::atomic::{AtomicUsize, Ordering}; use std::ops::Range; use std::os::raw::{c_void, c_char, c_float}; #[cfg(target_os = "android")] use std::os::raw::{c_int}; +use std::time::Duration; use gleam::gl; use webrender::api::*; use webrender::{ReadPixelsFormat, Renderer, RendererOptions, RendererStats, ThreadListener}; use webrender::{ExternalImage, ExternalImageHandler, ExternalImageSource}; use webrender::DebugFlags; use webrender::{ApiRecordingReceiver, BinaryRecorder}; use webrender::{AsyncPropertySampler, PipelineInfo, SceneBuilderHooks}; @@ -752,16 +753,19 @@ pub unsafe extern "C" fn wr_renderer_flu pub unsafe extern "C" fn wr_pipeline_info_delete(_info: WrPipelineInfo) { // _info will be dropped here, and the drop impl on FfiVec will free // the underlying vec memory } extern "C" { pub fn gecko_profiler_start_marker(name: *const c_char); pub fn gecko_profiler_end_marker(name: *const c_char); + pub fn gecko_profiler_add_text_marker( + name: *const c_char, text_bytes: *const c_char, text_len: usize, microseconds: u64); + pub fn gecko_profiler_thread_is_being_profiled() -> bool; } /// Simple implementation of the WR ProfilerHooks trait to allow profile /// markers to be seen in the Gecko profiler. struct GeckoProfilerHooks; impl ProfilerHooks for GeckoProfilerHooks { fn begin_marker(&self, label: &CStr) { @@ -770,16 +774,29 @@ impl ProfilerHooks for GeckoProfilerHook } } fn end_marker(&self, label: &CStr) { unsafe { gecko_profiler_end_marker(label.as_ptr()); } } + + fn add_text_marker(&self, label: &CStr, text: &str, duration: Duration) { + unsafe { + // NB: This can be as_micros() once we require Rust 1.33. + let micros = duration.subsec_micros() as u64 + duration.as_secs() * 1000 * 1000; + let text_bytes = text.as_bytes(); + gecko_profiler_add_text_marker(label.as_ptr(), text_bytes.as_ptr() as *const c_char, text_bytes.len(), micros); + } + } + + fn thread_is_being_profiled(&self) -> bool { + unsafe { gecko_profiler_thread_is_being_profiled() } + } } static PROFILER_HOOKS: GeckoProfilerHooks = GeckoProfilerHooks {}; #[allow(improper_ctypes)] // this is needed so that rustc doesn't complain about passing the &mut Transaction to an extern function extern "C" { // These callbacks are invoked from the scene builder thread (aka the APZ // updater thread)
--- a/gfx/webrender_bindings/webrender_ffi.h +++ b/gfx/webrender_bindings/webrender_ffi.h @@ -28,16 +28,19 @@ void gfx_critical_error(const char* msg) void gecko_printf_stderr_output(const char* msg); void* get_proc_address_from_glcontext(void* glcontext_ptr, const char* procname); void gecko_profiler_register_thread(const char* threadname); void gecko_profiler_unregister_thread(); void gecko_profiler_start_marker(const char* name); void gecko_profiler_end_marker(const char* name); +void gecko_profiler_add_text_marker( + const char* name, const char* text_ptr, size_t text_len, uint64_t microseconds); +bool gecko_profiler_thread_is_being_profiled(); // IMPORTANT: Keep this synchronized with enumerate_interners in // gfx/wr/webrender_api #define WEBRENDER_FOR_EACH_INTERNER(macro) \ macro(clip); \ macro(prim); \ macro(normal_border); \ macro(image_border); \
--- a/gfx/wr/webrender/src/device/gl.rs +++ b/gfx/wr/webrender/src/device/gl.rs @@ -5,16 +5,17 @@ use super::super::shader_source::SHADERS; use api::{ColorF, ImageDescriptor, ImageFormat, MemoryReport}; use api::{TextureTarget, VoidPtrToSizeFn}; use api::units::*; use euclid::Transform3D; use gleam::gl; use internal_types::{FastHashMap, LayerIndex, RenderTargetInfo}; use log::Level; +use profiler; use sha2::{Digest, Sha256}; use smallvec::SmallVec; use std::borrow::Cow; use std::cell::{Cell, RefCell}; use std::cmp; use std::collections::hash_map::Entry; use std::marker::PhantomData; use std::mem; @@ -23,16 +24,17 @@ use std::os::raw::c_void; use std::ops::Add; use std::path::PathBuf; use std::ptr; use std::rc::Rc; use std::slice; use std::sync::Arc; use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread; +use std::time::Duration; use webrender_build::shader::ProgramSourceDigest; use webrender_build::shader::{parse_shader_source, shader_source_from_file}; /// Sequence number for frames, as tracked by the device layer. #[derive(Debug, Copy, Clone, PartialEq, Ord, Eq, PartialOrd)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct GpuFrameId(usize); @@ -914,16 +916,21 @@ impl Drop for SharedDepthTarget { enum TexStorageUsage { Never, NonBGRA8, Always, } pub struct Device { gl: Rc<gl::Gl>, + + /// If non-None, |gl| points to a profiling wrapper, and this points to the + /// underling Gl instance. + base_gl: Option<Rc<gl::Gl>>, + // device state bound_textures: [gl::GLuint; 16], bound_program: gl::GLuint, bound_vao: gl::GLuint, bound_read_fbo: FBOId, bound_draw_fbo: FBOId, program_mode_id: UniformLocation, default_read_fbo: FBOId, @@ -1230,16 +1237,17 @@ impl Device { let optimal_pbo_stride = if renderer_name.contains("Adreno") { NonZeroUsize::new(256).unwrap() } else { NonZeroUsize::new(4).unwrap() }; Device { gl, + base_gl: None, resource_override_path, upload_method, inside_frame: false, capabilities: Capabilities { supports_multisampling: false, //TODO supports_copy_image_sub_data, supports_blit_to_texture_array, @@ -1358,16 +1366,32 @@ impl Device { Ok(id) } } pub fn begin_frame(&mut self) -> GpuFrameId { debug_assert!(!self.inside_frame); self.inside_frame = true; + // If our profiler state has changed, apply or remove the profiling + // wrapper from our GL context. + let being_profiled = profiler::thread_is_being_profiled(); + let using_wrapper = self.base_gl.is_some(); + if being_profiled && !using_wrapper { + fn note(name: &str, duration: Duration) { + profiler::add_text_marker(cstr!("OpenGL Calls"), name, duration); + } + let threshold = Duration::from_millis(1); + let wrapped = gl::ProfilingGl::wrap(self.gl.clone(), threshold, note); + let base = mem::replace(&mut self.gl, wrapped); + self.base_gl = Some(base); + } else if !being_profiled && using_wrapper { + self.gl = self.base_gl.take().unwrap(); + } + // Retrieve the currently set FBO. let mut default_read_fbo = [0]; unsafe { self.gl.get_integer_v(gl::READ_FRAMEBUFFER_BINDING, &mut default_read_fbo); } self.default_read_fbo = FBOId(default_read_fbo[0] as gl::GLuint); let mut default_draw_fbo = [0]; unsafe {
--- a/gfx/wr/webrender/src/profiler.rs +++ b/gfx/wr/webrender/src/profiler.rs @@ -6,16 +6,17 @@ use api::{ColorF, ColorU}; use debug_render::DebugRenderer; use device::query::{GpuSampler, GpuTimer, NamedTag}; use euclid::{Point2D, Rect, Size2D, vec2}; use internal_types::FastHashMap; use renderer::{MAX_VERTEX_TEXTURE_WIDTH, wr_has_been_initialized}; use std::collections::vec_deque::VecDeque; use std::{f32, mem}; use std::ffi::CStr; +use std::time::Duration; use time::precise_time_ns; const GRAPH_WIDTH: f32 = 1024.0; const GRAPH_HEIGHT: f32 = 320.0; const GRAPH_PADDING: f32 = 8.0; const GRAPH_FRAME_HEIGHT: f32 = 16.0; const PROFILE_PADDING: f32 = 10.0; @@ -25,20 +26,32 @@ const ONE_SECOND_NS: u64 = 1000000000; pub trait ProfilerHooks : Send + Sync { /// Called at the beginning of a profile scope. The label must /// be a C string (null terminated). fn begin_marker(&self, label: &CStr); /// Called at the end of a profile scope. The label must /// be a C string (null terminated). fn end_marker(&self, label: &CStr); + + /// Called with a duration to indicate a text marker that just ended. Text + /// markers allow different types of entries to be recorded on the same row + /// in the timeline, by adding labels to the entry. + /// + /// This variant is also useful when the caller only wants to record events + /// longer than a certain threshold, and thus they don't know in advance + /// whether the event will qualify. + fn add_text_marker(&self, label: &CStr, text: &str, duration: Duration); + + /// Returns true if the current thread is being profiled. + fn thread_is_being_profiled(&self) -> bool; } /// The current global profiler callbacks, if set by embedder. -static mut PROFILER_HOOKS: Option<&'static ProfilerHooks> = None; +pub static mut PROFILER_HOOKS: Option<&'static ProfilerHooks> = None; /// Set the profiler callbacks, or None to disable the profiler. /// This function must only ever be called before any WR instances /// have been created, or the hooks will not be set. pub fn set_profiler_hooks(hooks: Option<&'static ProfilerHooks>) { if !wr_has_been_initialized() { unsafe { PROFILER_HOOKS = hooks; @@ -46,16 +59,32 @@ pub fn set_profiler_hooks(hooks: Option< } } /// A simple RAII style struct to manage a profile scope. pub struct ProfileScope { name: &'static CStr, } +/// Records a marker of the given duration that just ended. +pub fn add_text_marker(label: &CStr, text: &str, duration: Duration) { + unsafe { + if let Some(ref hooks) = PROFILER_HOOKS { + hooks.add_text_marker(label, text, duration); + } + } +} + +/// Returns true if the current thread is being profiled. +pub fn thread_is_being_profiled() -> bool { + unsafe { + PROFILER_HOOKS.map_or(false, |h| h.thread_is_being_profiled()) + } +} + impl ProfileScope { /// Begin a new profile scope pub fn new(name: &'static CStr) -> Self { unsafe { if let Some(ref hooks) = PROFILER_HOOKS { hooks.begin_marker(name); } }