Bug 1671289 - Improve WebRender's integrated profiler. r=gw

In a (large-ish) nutshell:

 - Consolidate all counters under a single type.
 - Counters are all arranged in an array and referred to via index.
 - All counters can be displayed as average+max (float/int), graph, and change indicator.
 - Specify what to show and in what form via a pref.
 - All counters and visualizations support not having values every frame.
 - GPU time queries visualization is easier to read relative to the frame budget:
  - If the maximum value is under 16ms, the right side of the graph is fixed at 16ms.
  - If the maximum value is above 16ms, draw a vertical bar at 16ms.
 - Added a few new profile counters:
  - Total frame CPU time (from API send to the end of GPU command submission).
  - Visibility, Prepare, Batching and Glyph resolve times.

The main change is how profile counters are represented. Instead of having different types for different visualizations, every counter is represented the same way, tracking average/max values over half a ms and optionally recording a graph over a number of frames. Counters are stored in a vector and referred to via index (See constants at the top of profiler.rs).
The main motivation for this storage is to facilitate adding counters without having to think too much about where to store them and how to pass them to the renderer.

The profiler's UI is defined by a string with with a single syntax:
 - Comma separated list of tokens (leading and trailing spaces ignored), which can be:
  - A counter name:
   - If prefixed with a '#' character, the counter is shown as a graph.
   - If prefixed with a '*' character, the counter is shown as a change indicator
   - By default (counter name without prefix), the counter is shown as average and max over half a second.
  - A preset name:
   - A preset is a builtin UI string in the same syntax that can be nested in the main UI string.
   - Presets are defined towards the top of profiler.rs and can also refer to other presets.
  - An empty token adds a  bit of vertical space.
  - A '|' token begins a new column.
  - A '_' token begins a new row.

Differential Revision: https://phabricator.services.mozilla.com/D93603
This commit is contained in:
Nicolas Silva 2020-10-19 20:07:54 +00:00
Родитель 265eb412ec
Коммит b5e41f1e7e
43 изменённых файлов: 2052 добавлений и 2340 удалений

Просмотреть файл

@ -53,6 +53,7 @@ class gfxVarReceiver;
_(UseWebRenderOptimizedShaders, bool, false) \
_(UseWebRenderMultithreading, bool, false) \
_(UseWebRenderScissoredCacheClears, bool, true) \
_(WebRenderProfilerUI, nsCString, nsCString()) \
_(WebglAllowCoreProfile, bool, true) \
_(WebglAllowWindowsNativeGl, bool, false) \
_(WebRenderMaxPartialPresentRects, int32_t, 0) \

Просмотреть файл

@ -2044,6 +2044,7 @@ void CompositorBridgeParent::InitializeStatics() {
&UpdateWebRenderMultithreading);
gfxVars::SetWebRenderBatchingLookbackListener(
&UpdateWebRenderBatchingParameters);
gfxVars::SetWebRenderProfilerUIListener(&UpdateWebRenderProfilerUI);
}
/*static*/
@ -2122,6 +2123,17 @@ void CompositorBridgeParent::UpdateWebRenderBatchingParameters() {
});
}
/*static*/
void CompositorBridgeParent::UpdateWebRenderProfilerUI() {
if (!sIndirectLayerTreesLock) {
return;
}
MonitorAutoLock lock(*sIndirectLayerTreesLock);
ForEachWebRenderBridgeParent([&](WebRenderBridgeParent* wrBridge) -> void {
wrBridge->UpdateProfilerUI();
});
}
RefPtr<WebRenderBridgeParent> CompositorBridgeParent::GetWebRenderBridgeParent()
const {
return mWrBridge;

Просмотреть файл

@ -735,6 +735,11 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase,
*/
static void UpdateWebRenderBatchingParameters();
/**
* Notify the compositor webrender profiler UI string has been updated.
*/
static void UpdateWebRenderProfilerUI();
/**
* Wrap the data structure to be sent over IPC.
*/

Просмотреть файл

@ -362,9 +362,9 @@ WebRenderBridgeParent::WebRenderBridgeParent(
MOZ_ASSERT(!mCompositorScheduler);
mCompositorScheduler = new CompositorVsyncScheduler(this, mWidget);
}
UpdateDebugFlags();
UpdateQualitySettings();
UpdateProfilerUI();
}
WebRenderBridgeParent::WebRenderBridgeParent(const wr::PipelineId& aPipelineId,
@ -1500,6 +1500,11 @@ void WebRenderBridgeParent::UpdateDebugFlags() {
mApi->UpdateDebugFlags(gfxVars::WebRenderDebugFlags());
}
void WebRenderBridgeParent::UpdateProfilerUI() {
nsCString uiString = gfxVars::GetWebRenderProfilerUIOrDefault();
mApi->SetProfilerUI(uiString);
}
void WebRenderBridgeParent::UpdateMultithreading() {
mApi->EnableMultithreading(gfxVars::UseWebRenderMultithreading());
}

Просмотреть файл

@ -130,6 +130,7 @@ class WebRenderBridgeParent final : public PWebRenderBridgeParent,
void UpdateDebugFlags();
void UpdateMultithreading();
void UpdateBatchingParameters();
void UpdateProfilerUI();
mozilla::ipc::IPCResult RecvEnsureConnected(
TextureFactoryIdentifier* aTextureFactoryIdentifier,

Просмотреть файл

@ -570,6 +570,14 @@ void RecordingPrefChanged(const char* aPrefName, void* aClosure) {
#define WR_DEBUG_PREF "gfx.webrender.debug"
static void WebRendeProfilerUIPrefChangeCallback(const char* aPrefName, void*) {
nsCString uiString;
if (NS_SUCCEEDED(Preferences::GetCString("gfx.webrender.debug.profiler-ui",
uiString))) {
gfxVars::SetWebRenderProfilerUI(uiString);
}
}
static void WebRenderDebugPrefChangeCallback(const char* aPrefName, void*) {
wr::DebugFlags flags{0};
#define GFX_WEBRENDER_DEBUG(suffix, bit) \
@ -584,18 +592,11 @@ static void WebRenderDebugPrefChangeCallback(const char* aPrefName, void*) {
GFX_WEBRENDER_DEBUG(".gpu-sample-queries", wr::DebugFlags::GPU_SAMPLE_QUERIES)
GFX_WEBRENDER_DEBUG(".disable-batching", wr::DebugFlags::DISABLE_BATCHING)
GFX_WEBRENDER_DEBUG(".epochs", wr::DebugFlags::EPOCHS)
GFX_WEBRENDER_DEBUG(".compact-profiler", wr::DebugFlags::COMPACT_PROFILER)
GFX_WEBRENDER_DEBUG(".smart-profiler", wr::DebugFlags::SMART_PROFILER)
GFX_WEBRENDER_DEBUG(".echo-driver-messages",
wr::DebugFlags::ECHO_DRIVER_MESSAGES)
GFX_WEBRENDER_DEBUG(".new-frame-indicator",
wr::DebugFlags::NEW_FRAME_INDICATOR)
GFX_WEBRENDER_DEBUG(".new-scene-indicator",
wr::DebugFlags::NEW_SCENE_INDICATOR)
GFX_WEBRENDER_DEBUG(".show-overdraw", wr::DebugFlags::SHOW_OVERDRAW)
GFX_WEBRENDER_DEBUG(".gpu-cache", wr::DebugFlags::GPU_CACHE_DBG)
GFX_WEBRENDER_DEBUG(".slow-frame-indicator",
wr::DebugFlags::SLOW_FRAME_INDICATOR)
GFX_WEBRENDER_DEBUG(".texture-cache.clear-evicted",
wr::DebugFlags::TEXTURE_CACHE_DBG_CLEAR_EVICTED)
GFX_WEBRENDER_DEBUG(".picture-caching", wr::DebugFlags::PICTURE_CACHING_DBG)
@ -1385,6 +1386,8 @@ void gfxPlatform::ShutdownLayersIPC() {
Preferences::UnregisterCallback(WebRenderDebugPrefChangeCallback,
WR_DEBUG_PREF);
Preferences::UnregisterCallback(WebRendeProfilerUIPrefChangeCallback,
"gfx.webrender.debug.profiler-ui");
}
} else {
@ -2796,6 +2799,9 @@ void gfxPlatform::InitWebRenderConfig() {
Preferences::RegisterPrefixCallbackAndCall(WebRenderDebugPrefChangeCallback,
WR_DEBUG_PREF);
Preferences::RegisterPrefixCallbackAndCall(
WebRendeProfilerUIPrefChangeCallback,
"gfx.webrender.debug.profiler-ui");
Preferences::RegisterCallback(
WebRenderQualityPrefChangeCallback,
nsDependentCString(

Просмотреть файл

@ -394,6 +394,24 @@ void RenderThread::SetClearColor(wr::WindowId aWindowId, wr::ColorF aColor) {
}
}
void RenderThread::SetProfilerUI(wr::WindowId aWindowId, nsCString aUI) {
if (mHasShutdown) {
return;
}
if (!IsInRenderThread()) {
Loop()->PostTask(NewRunnableMethod<wr::WindowId, nsCString>(
"wr::RenderThread::SetProfilerUI", this, &RenderThread::SetProfilerUI,
aWindowId, aUI));
return;
}
auto it = mRenderers.find(aWindowId);
if (it != mRenderers.end()) {
it->second->SetProfilerUI(aUI);
}
}
void RenderThread::RunEvent(wr::WindowId aWindowId,
UniquePtr<RendererEvent> aEvent) {
if (!IsInRenderThread()) {

Просмотреть файл

@ -179,6 +179,9 @@ class RenderThread final {
/// Automatically forwarded to the render thread.
void SetClearColor(wr::WindowId aWindowId, wr::ColorF aColor);
/// Automatically forwarded to the render thread.
void SetProfilerUI(wr::WindowId aWindowId, nsCString aUI);
/// Automatically forwarded to the render thread.
void PipelineSizeChanged(wr::WindowId aWindowId, uint64_t aPipelineId,
float aWidth, float aHeight);

Просмотреть файл

@ -436,5 +436,10 @@ void RendererOGL::AccumulateMemoryReport(MemoryReport* aReport) {
aReport->swap_chain += swapChainSize;
}
void RendererOGL::SetProfilerUI(const nsCString& aUI) {
wr_renderer_set_profiler_ui(GetRenderer(), (const uint8_t*)aUI.get(),
aUI.Length());
}
} // namespace wr
} // namespace mozilla

Просмотреть файл

@ -115,6 +115,8 @@ class RendererOGL {
void AccumulateMemoryReport(MemoryReport* aReport);
void SetProfilerUI(const nsCString& aUI);
wr::Renderer* GetRenderer() { return mRenderer; }
gl::GLContext* gl() const;

Просмотреть файл

@ -542,6 +542,10 @@ void WebRenderAPI::SetClearColor(const gfx::DeviceColor& aColor) {
RenderThread::Get()->SetClearColor(mId, ToColorF(aColor));
}
void WebRenderAPI::SetProfilerUI(const nsCString& aUIString) {
RenderThread::Get()->SetProfilerUI(mId, aUIString);
}
void WebRenderAPI::Pause() {
class PauseEvent : public RendererEvent {
public:

Просмотреть файл

@ -258,6 +258,7 @@ class WebRenderAPI final {
void SetBatchingLookback(uint32_t aCount);
void SetClearColor(const gfx::DeviceColor& aColor);
void SetProfilerUI(const nsCString& aUIString);
void Pause();
bool Resume();

Просмотреть файл

@ -743,6 +743,14 @@ pub unsafe extern "C" fn wr_renderer_readback(
renderer.read_pixels_into(FramebufferIntSize::new(width, height).into(), format, &mut slice);
}
#[no_mangle]
pub unsafe extern "C" fn wr_renderer_set_profiler_ui(renderer: &mut Renderer, ui_str: *const u8, ui_str_len: usize) {
let slice = std::slice::from_raw_parts(ui_str, ui_str_len);
if let Ok(ui_str) = std::str::from_utf8(slice) {
renderer.set_profiler_ui(ui_str);
}
}
#[no_mangle]
pub unsafe extern "C" fn wr_renderer_delete(renderer: *mut Renderer) {
let renderer = Box::from_raw(renderer);

Просмотреть файл

@ -254,14 +254,10 @@ pub fn main_wrapper<E: Example>(
winit::VirtualKeyCode::P => debug_flags.toggle(DebugFlags::PROFILER_DBG),
winit::VirtualKeyCode::O => debug_flags.toggle(DebugFlags::RENDER_TARGET_DBG),
winit::VirtualKeyCode::I => debug_flags.toggle(DebugFlags::TEXTURE_CACHE_DBG),
winit::VirtualKeyCode::S => debug_flags.toggle(DebugFlags::COMPACT_PROFILER),
winit::VirtualKeyCode::T => debug_flags.toggle(DebugFlags::PICTURE_CACHING_DBG),
winit::VirtualKeyCode::Q => debug_flags.toggle(
DebugFlags::GPU_TIME_QUERIES | DebugFlags::GPU_SAMPLE_QUERIES
),
winit::VirtualKeyCode::F => debug_flags.toggle(
DebugFlags::NEW_FRAME_INDICATOR | DebugFlags::NEW_SCENE_INDICATOR
),
winit::VirtualKeyCode::G => debug_flags.toggle(DebugFlags::GPU_CACHE_DBG),
winit::VirtualKeyCode::Key1 => txn.set_document_view(
device_size.into(),

Просмотреть файл

@ -218,7 +218,6 @@ fn main() {
};
let opts = webrender::RendererOptions {
debug_flags: webrender::DebugFlags::NEW_FRAME_INDICATOR | webrender::DebugFlags::NEW_SCENE_INDICATOR,
..Default::default()
};

Просмотреть файл

@ -10,6 +10,7 @@ use crate::api::SharedFontInstanceMap;
use crate::api::units::*;
use crate::render_api::{ResourceUpdate, TransactionMsg, AddFont};
use crate::image_tiling::*;
use crate::profiler;
use std::collections::HashMap;
use std::sync::Arc;
@ -164,6 +165,8 @@ impl ApiResources {
}
let (rasterizer, requests) = self.create_blob_scene_builder_requests(&blobs_to_rasterize);
transaction.profile.set(profiler::RASTERIZED_BLOBS, blobs_to_rasterize.len());
transaction.profile.set(profiler::RASTERIZED_BLOB_TILES, requests.len());
transaction.use_scene_builder_thread |= !requests.is_empty();
transaction.use_scene_builder_thread |= !transaction.scene_ops.is_empty();
transaction.blob_rasterizer = rasterizer;

Просмотреть файл

@ -1400,6 +1400,7 @@ impl intern::Internable for ClipIntern {
type Key = ClipItemKey;
type StoreData = ClipNode;
type InternData = ClipInternData;
const PROFILE_COUNTER: usize = crate::profiler::INTERNED_CLIPS;
}
#[derive(Debug, MallocSizeOf)]

Просмотреть файл

@ -162,6 +162,7 @@ impl intern::Internable for FilterDataIntern {
type Key = SFilterDataKey;
type StoreData = SFilterDataTemplate;
type InternData = ();
const PROFILE_COUNTER: usize = crate::profiler::INTERNED_FILTER_DATA;
}
fn push_component_transfer_data(

Просмотреть файл

@ -19,7 +19,7 @@ use crate::picture::{BackdropKind, SubpixelMode, TileCacheLogger, RasterConfig,
use crate::prepare::prepare_primitives;
use crate::prim_store::{PictureIndex, PrimitiveDebugId};
use crate::prim_store::{DeferredResolve};
use crate::profiler::{FrameProfileCounters, TextureCacheProfileCounters, ResourceProfileCounters};
use crate::profiler::{self, TransactionProfile};
use crate::render_backend::{DataStores, FrameStamp, FrameId, ScratchBuffer};
use crate::render_target::{RenderTarget, PictureCacheTarget, TextureCacheRenderTarget};
use crate::render_target::{RenderTargetContext, RenderTargetKind};
@ -176,7 +176,6 @@ pub struct FrameBuildingContext<'a> {
pub struct FrameBuildingState<'a> {
pub render_tasks: &'a mut RenderTaskGraph,
pub profile_counters: &'a mut FrameProfileCounters,
pub clip_store: &'a mut ClipStore,
pub resource_cache: &'a mut ResourceCache,
pub gpu_cache: &'a mut GpuCache,
@ -185,6 +184,7 @@ pub struct FrameBuildingState<'a> {
pub surfaces: &'a mut Vec<SurfaceInfo>,
pub dirty_region_stack: Vec<DirtyRegion>,
pub composite_state: &'a mut CompositeState,
pub num_visible_primitives: u32,
}
impl<'a> FrameBuildingState<'a> {
@ -248,17 +248,16 @@ impl FrameBuilder {
resource_cache: &mut ResourceCache,
gpu_cache: &mut GpuCache,
render_tasks: &mut RenderTaskGraph,
profile_counters: &mut FrameProfileCounters,
global_device_pixel_scale: DevicePixelScale,
scene_properties: &SceneProperties,
transform_palette: &mut TransformPalette,
data_stores: &mut DataStores,
scratch: &mut ScratchBuffer,
debug_flags: DebugFlags,
texture_cache_profile: &mut TextureCacheProfileCounters,
composite_state: &mut CompositeState,
tile_cache_logger: &mut TileCacheLogger,
tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>,
profile: &mut TransactionProfile,
) -> Option<RenderTaskId> {
profile_scope!("build_layer_screen_rects_and_cull_layers");
@ -335,6 +334,7 @@ impl FrameBuilder {
{
profile_scope!("UpdateVisibility");
profile_marker!("UpdateVisibility");
profile.start_time(profiler::FRAME_VISIBILITY_TIME);
let visibility_context = FrameVisibilityContext {
global_device_pixel_scale,
@ -371,11 +371,14 @@ impl FrameBuilder {
visibility_state.scratch.frame.clip_chain_stack = visibility_state.clip_chain_stack.take();
visibility_state.scratch.frame.surface_stack = visibility_state.surface_stack.take();
profile.end_time(profiler::FRAME_VISIBILITY_TIME);
}
profile.start_time(profiler::FRAME_PREPARE_TIME);
let mut frame_state = FrameBuildingState {
render_tasks,
profile_counters,
clip_store: &mut scene.clip_store,
resource_cache,
gpu_cache,
@ -384,6 +387,7 @@ impl FrameBuilder {
surfaces: &mut surfaces,
dirty_region_stack: scratch.frame.dirty_region_stack.take(),
composite_state,
num_visible_primitives: 0,
};
frame_state
@ -453,6 +457,8 @@ impl FrameBuilder {
);
frame_state.pop_dirty_region();
profile.end_time(profiler::FRAME_PREPARE_TIME);
profile.set(profiler::VISIBLE_PRIMITIVES, frame_state.num_visible_primitives);
scratch.frame.dirty_region_stack = frame_state.dirty_region_stack.take();
scratch.frame.surfaces = surfaces.take();
@ -460,9 +466,11 @@ impl FrameBuilder {
{
profile_marker!("BlockOnResources");
resource_cache.block_until_all_resources_added(gpu_cache,
render_tasks,
texture_cache_profile);
resource_cache.block_until_all_resources_added(
gpu_cache,
render_tasks,
profile,
);
}
Some(root_render_task_id)
@ -478,7 +486,6 @@ impl FrameBuilder {
layer: DocumentLayer,
device_origin: DeviceIntPoint,
pan: WorldPoint,
resource_profile: &mut ResourceProfileCounters,
scene_properties: &SceneProperties,
data_stores: &mut DataStores,
scratch: &mut ScratchBuffer,
@ -487,15 +494,13 @@ impl FrameBuilder {
tile_cache_logger: &mut TileCacheLogger,
tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>,
dirty_rects_are_valid: bool,
profile: &mut TransactionProfile,
) -> Frame {
profile_scope!("build");
profile_marker!("BuildFrame");
let mut profile_counters = FrameProfileCounters::new();
profile_counters
.total_primitives
.set(scene.prim_store.prim_count());
resource_profile.picture_cache_slices.set(scene.tile_cache_config.picture_cache_slice_count);
profile.set(profiler::PRIMITIVES, scene.prim_store.prim_count());
profile.set(profiler::PICTURE_CACHE_SLICES, scene.tile_cache_config.picture_cache_slice_count);
resource_cache.begin_frame(stamp);
gpu_cache.begin_frame(stamp);
@ -532,19 +537,20 @@ impl FrameBuilder {
resource_cache,
gpu_cache,
&mut render_tasks,
&mut profile_counters,
global_device_pixel_scale,
scene_properties,
&mut transform_palette,
data_stores,
scratch,
debug_flags,
&mut resource_profile.texture_cache,
&mut composite_state,
tile_cache_logger,
tile_caches,
profile,
);
profile.start_time(profiler::FRAME_BATCHING_TIME);
let mut passes;
let mut deferred_resolves = vec![];
let mut has_texture_cache_tasks = false;
@ -611,11 +617,13 @@ impl FrameBuilder {
}
}
let gpu_cache_frame_id = gpu_cache.end_frame(&mut resource_profile.gpu_cache).frame_id();
profile.end_time(profiler::FRAME_BATCHING_TIME);
let gpu_cache_frame_id = gpu_cache.end_frame(profile).frame_id();
render_tasks.write_task_data();
*render_task_counters = render_tasks.counters();
resource_cache.end_frame(&mut resource_profile.texture_cache);
resource_cache.end_frame(profile);
self.prim_headers_prealloc.record_vec(&mut prim_headers.headers_int);
self.composite_state_prealloc.record(&composite_state);
@ -627,7 +635,6 @@ impl FrameBuilder {
scene.output_rect.size,
),
layer,
profile_counters,
passes,
transform_palette: transform_palette.finish(),
render_tasks,
@ -988,8 +995,6 @@ pub struct Frame {
pub device_rect: DeviceIntRect,
pub layer: DocumentLayer,
pub passes: Vec<RenderPass>,
#[cfg_attr(any(feature = "capture", feature = "replay"), serde(default = "FrameProfileCounters::new", skip))]
pub profile_counters: FrameProfileCounters,
pub transform_palette: Vec<TransformData>,
pub render_tasks: RenderTaskGraph,

Просмотреть файл

@ -19,7 +19,7 @@ use crate::texture_cache::{TextureCache, TextureCacheHandle, Eviction};
use crate::gpu_cache::GpuCache;
use crate::render_task_graph::RenderTaskGraph;
use crate::render_task_cache::RenderTaskCache;
use crate::profiler::TextureCacheProfileCounters;
use crate::profiler::{self, TransactionProfile};
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use rayon::ThreadPool;
use rayon::prelude::*;
@ -100,6 +100,7 @@ impl GlyphRasterizer {
// Increment the total number of glyphs that are pending. This is used to determine
// later whether to use worker threads for the remaining glyphs during resolve time.
self.pending_glyph_count += 1;
self.glyph_request_count += 1;
// Find a batch container for the font instance for this glyph. Use get_mut to avoid
// cloning the font instance, since this is the common path.
@ -219,8 +220,10 @@ impl GlyphRasterizer {
gpu_cache: &mut GpuCache,
_: &mut RenderTaskCache,
_: &mut RenderTaskGraph,
_: &mut TextureCacheProfileCounters,
profile: &mut TransactionProfile,
) {
profile.start_time(profiler::GLYPH_RESOLVE_TIME);
// Work around the borrow checker, since we call flush_glyph_requests below
let mut pending_glyph_requests = mem::replace(
&mut self.pending_glyph_requests,
@ -241,6 +244,11 @@ impl GlyphRasterizer {
debug_assert_eq!(self.pending_glyph_count, 0);
debug_assert!(self.pending_glyph_requests.is_empty());
if self.glyph_request_count > 0 {
profile.set(profiler::RASTERIZED_GLYPHS, self.glyph_request_count);
self.glyph_request_count = 0;
}
profile_scope!("resolve_glyphs");
// Pull rasterized glyphs from the queue and update the caches.
while self.pending_glyph_jobs > 0 {
@ -307,6 +315,8 @@ impl GlyphRasterizer {
// Now that we are done with the critical path (rendering the glyphs),
// we can schedule removing the fonts if needed.
self.remove_dead_fonts();
profile.end_time(profiler::GLYPH_RESOLVE_TIME);
}
}
@ -936,6 +946,9 @@ pub struct GlyphRasterizer {
/// The current number of glyph request jobs that have been kicked to worker threads.
pending_glyph_jobs: usize,
/// The number of glyphs requested this frame.
glyph_request_count: usize,
/// A map of current glyph request batches.
pending_glyph_requests: FastHashMap<FontInstance, SmallVec<[GlyphKey; 16]>>,
@ -980,6 +993,7 @@ impl GlyphRasterizer {
font_contexts: Arc::new(font_context),
pending_glyph_jobs: 0,
pending_glyph_count: 0,
glyph_request_count: 0,
glyph_rx,
glyph_tx,
workers,
@ -1060,6 +1074,7 @@ impl GlyphRasterizer {
//TODO: any signals need to be sent to the workers?
self.pending_glyph_jobs = 0;
self.pending_glyph_count = 0;
self.glyph_request_count = 0;
self.fonts_to_remove.clear();
self.font_instances_to_remove.clear();
}
@ -1122,7 +1137,7 @@ mod test_glyph_rasterizer {
use crate::gpu_cache::GpuCache;
use crate::render_task_cache::RenderTaskCache;
use crate::render_task_graph::{RenderTaskGraph, RenderTaskGraphCounters};
use crate::profiler::TextureCacheProfileCounters;
use crate::profiler::TransactionProfile;
use api::{FontKey, FontInstanceKey, FontSize, FontTemplate, FontRenderMode,
IdNamespace, ColorU};
use api::units::DevicePoint;
@ -1193,7 +1208,7 @@ mod test_glyph_rasterizer {
&mut gpu_cache,
&mut render_task_cache,
&mut render_task_tree,
&mut TextureCacheProfileCounters::new(),
&mut TransactionProfile::new(),
);
}

Просмотреть файл

@ -30,7 +30,7 @@ use api::IdNamespace;
use api::units::*;
use euclid::{HomogeneousVector, Rect};
use crate::internal_types::{FastHashMap, FastHashSet};
use crate::profiler::GpuCacheProfileCounters;
use crate::profiler::{self, TransactionProfile};
use crate::render_backend::{FrameStamp, FrameId};
use crate::prim_store::VECS_PER_SEGMENT;
use crate::renderer::MAX_VERTEX_TEXTURE_WIDTH;
@ -865,18 +865,12 @@ impl GpuCache {
/// device specific cache texture.
pub fn end_frame(
&mut self,
profile_counters: &mut GpuCacheProfileCounters,
profile: &mut TransactionProfile,
) -> FrameStamp {
profile_scope!("end_frame");
profile_counters
.allocated_rows
.set(self.texture.rows.len());
profile_counters
.allocated_blocks
.set(self.texture.allocated_block_count);
profile_counters
.saved_blocks
.set(self.saved_block_count);
profile.set(profiler::GPU_CACHE_ROWS_TOTAL, self.texture.rows.len());
profile.set(profiler::GPU_CACHE_BLOCKS_TOTAL, self.texture.allocated_block_count);
profile.set(profiler::GPU_CACHE_BLOCKS_SAVED, self.saved_block_count);
let reached_threshold =
self.texture.rows.len() > (GPU_CACHE_INITIAL_HEIGHT as usize) &&

Просмотреть файл

@ -35,12 +35,12 @@
use crate::internal_types::FastHashMap;
use malloc_size_of::MallocSizeOf;
use crate::profiler::ResourceProfileCounter;
use std::fmt::Debug;
use std::hash::Hash;
use std::marker::PhantomData;
use std::{mem, ops, u64};
use std::{ops, u64};
use crate::util::VecHelper;
use crate::profiler::TransactionProfile;
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
@ -166,7 +166,7 @@ impl<I: Internable> DataStore<I> {
pub fn apply_updates(
&mut self,
update_list: UpdateList<I::Key>,
profile_counter: &mut ResourceProfileCounter,
profile: &mut TransactionProfile,
) {
for insertion in update_list.insertions {
self.items
@ -178,8 +178,7 @@ impl<I: Internable> DataStore<I> {
self.items[removal.index] = None;
}
let per_item_size = mem::size_of::<I::Key>() + mem::size_of::<I::StoreData>();
profile_counter.set(self.items.len(), per_item_size * self.items.len());
profile.set(I::PROFILE_COUNTER, self.items.len());
}
}
@ -460,4 +459,7 @@ pub trait Internable: MallocSizeOf {
type Key: Eq + Hash + Clone + Debug + MallocSizeOf + InternDebug + InternSerialize + for<'a> InternDeserialize<'a>;
type StoreData: From<Self::Key> + MallocSizeOf + InternSerialize + for<'a> InternDeserialize<'a>;
type InternData: MallocSizeOf + InternSerialize + for<'a> InternDeserialize<'a>;
// Profile counter indices, see the list in profiler.rs
const PROFILE_COUNTER: usize;
}

Просмотреть файл

@ -12,9 +12,9 @@ use crate::device::TextureFilter;
use crate::renderer::PipelineInfo;
use crate::gpu_cache::GpuCacheUpdateList;
use crate::frame_builder::Frame;
use crate::profiler::TransactionProfile;
use fxhash::FxHasher;
use plane_split::BspSplitter;
use crate::profiler::BackendProfileCounters;
use smallvec::SmallVec;
use std::{usize, i32};
use std::collections::{HashMap, HashSet};
@ -539,6 +539,7 @@ impl ResourceUpdateList {
pub struct RenderedDocument {
pub frame: Frame,
pub is_new_scene: bool,
pub profile: TransactionProfile,
}
pub enum DebugOutput {
@ -565,7 +566,6 @@ pub enum ResultMsg {
DocumentId,
RenderedDocument,
ResourceUpdateList,
BackendProfileCounters,
),
AppendNotificationRequests(Vec<NotificationRequest>),
ForceRedraw,

Просмотреть файл

@ -128,7 +128,7 @@ pub fn prepare_primitives(
tile_cache_log,
tile_caches,
) {
frame_state.profile_counters.visible_primitives.inc();
frame_state.num_visible_primitives += 1;
} else {
prim_instance.clear_visibility();
}

Просмотреть файл

@ -74,6 +74,7 @@ impl Internable for Backdrop {
type Key = BackdropKey;
type StoreData = BackdropTemplate;
type InternData = ();
const PROFILE_COUNTER: usize = crate::profiler::INTERNED_BACKDROPS;
}
impl InternablePrimitive for Backdrop {

Просмотреть файл

@ -145,6 +145,7 @@ impl intern::Internable for NormalBorderPrim {
type Key = NormalBorderKey;
type StoreData = NormalBorderTemplate;
type InternData = ();
const PROFILE_COUNTER: usize = crate::profiler::INTERNED_NORMAL_BORDERS;
}
impl InternablePrimitive for NormalBorderPrim {
@ -318,6 +319,7 @@ impl intern::Internable for ImageBorder {
type Key = ImageBorderKey;
type StoreData = ImageBorderTemplate;
type InternData = ();
const PROFILE_COUNTER: usize = crate::profiler::INTERNED_IMAGE_BORDERS;
}
impl InternablePrimitive for ImageBorder {

Просмотреть файл

@ -321,6 +321,7 @@ impl Internable for LinearGradient {
type Key = LinearGradientKey;
type StoreData = LinearGradientTemplate;
type InternData = ();
const PROFILE_COUNTER: usize = crate::profiler::INTERNED_LINEAR_GRADIENTS;
}
impl InternablePrimitive for LinearGradient {
@ -550,6 +551,7 @@ impl Internable for RadialGradient {
type Key = RadialGradientKey;
type StoreData = RadialGradientTemplate;
type InternData = ();
const PROFILE_COUNTER: usize = crate::profiler::INTERNED_RADIAL_GRADIENTS;
}
impl InternablePrimitive for RadialGradient {
@ -769,6 +771,7 @@ impl Internable for ConicGradient {
type Key = ConicGradientKey;
type StoreData = ConicGradientTemplate;
type InternData = ();
const PROFILE_COUNTER: usize = crate::profiler::INTERNED_CONIC_GRADIENTS;
}
impl InternablePrimitive for ConicGradient {

Просмотреть файл

@ -288,6 +288,7 @@ impl Internable for Image {
type Key = ImageKey;
type StoreData = ImageTemplate;
type InternData = ();
const PROFILE_COUNTER: usize = crate::profiler::INTERNED_IMAGES;
}
impl InternablePrimitive for Image {
@ -460,6 +461,7 @@ impl Internable for YuvImage {
type Key = YuvImageKey;
type StoreData = YuvImageTemplate;
type InternData = ();
const PROFILE_COUNTER: usize = crate::profiler::INTERNED_YUV_IMAGES;
}
impl InternablePrimitive for YuvImage {

Просмотреть файл

@ -126,6 +126,7 @@ impl intern::Internable for LineDecoration {
type Key = LineDecorationKey;
type StoreData = LineDecorationTemplate;
type InternData = ();
const PROFILE_COUNTER: usize = crate::profiler::INTERNED_LINE_DECORATIONS;
}
impl InternablePrimitive for LineDecoration {

Просмотреть файл

@ -577,6 +577,7 @@ impl intern::Internable for PrimitiveKeyKind {
type Key = PrimitiveKey;
type StoreData = PrimitiveTemplate;
type InternData = ();
const PROFILE_COUNTER: usize = crate::profiler::INTERNED_PRIMITIVES;
}
impl InternablePrimitive for PrimitiveKeyKind {

Просмотреть файл

@ -277,6 +277,7 @@ impl Internable for Picture {
type Key = PictureKey;
type StoreData = PictureTemplate;
type InternData = ();
const PROFILE_COUNTER: usize = crate::profiler::INTERNED_PICTURES;
}
impl InternablePrimitive for Picture {

Просмотреть файл

@ -151,6 +151,7 @@ impl intern::Internable for TextRun {
type Key = TextRunKey;
type StoreData = TextRunTemplate;
type InternData = ();
const PROFILE_COUNTER: usize = crate::profiler::INTERNED_TEXT_RUNS;
}
impl InternablePrimitive for TextRun {

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -27,6 +27,7 @@ use crate::api::units::*;
use crate::api_resources::ApiResources;
use crate::scene_builder_thread::{SceneBuilderRequest, SceneBuilderResult};
use crate::intern::InterningMemoryReport;
use crate::profiler::{self, TransactionProfile};
#[repr(C)]
#[derive(Clone, Copy, Debug)]
@ -388,6 +389,7 @@ impl Transaction {
blob_rasterizer: None,
blob_requests: Vec::new(),
rasterized_blobs: Vec::new(),
profile: TransactionProfile::new(),
})
}
@ -571,6 +573,8 @@ pub struct TransactionMsg {
pub blob_requests: Vec<BlobImageParams>,
///
pub rasterized_blobs: Vec<(BlobImageRequest, BlobImageResult)>,
/// Collect various data along the rendering pipeline to display it in the embedded profiler.
pub profile: TransactionProfile,
}
impl fmt::Debug for TransactionMsg {
@ -1232,6 +1236,7 @@ impl RenderApi {
blob_rasterizer: None,
blob_requests: Vec::new(),
rasterized_blobs: Vec::new(),
profile: TransactionProfile::new(),
})
}
@ -1250,6 +1255,7 @@ impl RenderApi {
blob_rasterizer: None,
blob_requests: Vec::new(),
rasterized_blobs: Vec::new(),
profile: TransactionProfile::new(),
})
}
@ -1280,6 +1286,10 @@ impl RenderApi {
self.resources.update(&mut transaction);
transaction.use_scene_builder_thread |= !transaction.scene_ops.is_empty();
if transaction.generate_frame {
transaction.profile.start_time(profiler::API_SEND_TIME);
transaction.profile.start_time(profiler::TOTAL_FRAME_CPU_TIME);
}
if transaction.use_scene_builder_thread {
let sender = if transaction.low_priority {
@ -1301,6 +1311,10 @@ impl RenderApi {
.map(|(txn, id)| {
let mut txn = txn.finalize(id);
self.resources.update(&mut txn);
if txn.generate_frame {
txn.profile.start_time(profiler::API_SEND_TIME);
txn.profile.start_time(profiler::TOTAL_FRAME_CPU_TIME);
}
txn
})

Просмотреть файл

@ -38,7 +38,7 @@ use crate::picture::{TileCacheLogger, PictureScratchBuffer, SliceId, TileCacheIn
use crate::prim_store::{PrimitiveScratchBuffer, PrimitiveInstance};
use crate::prim_store::{PrimitiveInstanceKind, PrimTemplateCommonData, PrimitiveStore};
use crate::prim_store::interned::*;
use crate::profiler::{BackendProfileCounters, ResourceProfileCounters};
use crate::profiler::{self, TransactionProfile};
use crate::render_task_graph::RenderTaskGraphCounters;
use crate::renderer::{AsyncPropertySampler, PipelineInfo};
use crate::resource_cache::ResourceCache;
@ -274,12 +274,12 @@ macro_rules! declare_data_stores {
fn apply_updates(
&mut self,
updates: InternerUpdates,
profile_counters: &mut BackendProfileCounters,
profile: &mut TransactionProfile,
) {
$(
self.$name.apply_updates(
updates.$name,
&mut profile_counters.intern.$name,
profile,
);
)+
}
@ -470,6 +470,8 @@ struct Document {
/// Tracks if we need to invalidate dirty rects for this document, due to the picture
/// cache slice configuration having changed when a new scene is swapped in.
dirty_rects_are_valid: bool,
profile: TransactionProfile,
}
impl Document {
@ -512,6 +514,7 @@ impl Document {
loaded_scene: Scene::new(),
prev_composite_descriptor: CompositeDescriptor::empty(),
dirty_rects_are_valid: true,
profile: TransactionProfile::new(),
}
}
@ -603,11 +606,12 @@ impl Document {
&mut self,
resource_cache: &mut ResourceCache,
gpu_cache: &mut GpuCache,
resource_profile: &mut ResourceProfileCounters,
debug_flags: DebugFlags,
tile_cache_logger: &mut TileCacheLogger,
tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>,
) -> RenderedDocument {
self.profile.start_time(profiler::FRAME_BUILDING_TIME);
let accumulated_scale_factor = self.view.accumulated_scale_factor();
let pan = self.view.frame.pan.to_f32() / accumulated_scale_factor;
@ -627,7 +631,6 @@ impl Document {
self.view.scene.layer,
self.view.scene.device_rect.origin,
pan,
resource_profile,
&self.dynamic_properties,
&mut self.data_stores,
&mut self.scratch,
@ -636,6 +639,7 @@ impl Document {
tile_cache_logger,
tile_caches,
self.dirty_rects_are_valid,
&mut self.profile,
);
frame
@ -647,9 +651,12 @@ impl Document {
let is_new_scene = self.has_built_scene;
self.has_built_scene = false;
self.profile.end_time(profiler::FRAME_BUILDING_TIME);
RenderedDocument {
frame,
is_new_scene,
profile: self.profile.take_and_reset(),
}
}
@ -875,7 +882,7 @@ impl RenderBackend {
IdNamespace(NEXT_NAMESPACE_ID.fetch_add(1, Ordering::Relaxed) as u32)
}
pub fn run(&mut self, mut profile_counters: BackendProfileCounters) {
pub fn run(&mut self) {
let mut frame_counter: u32 = 0;
let mut status = RenderBackendStatus::Continue;
@ -886,7 +893,7 @@ impl RenderBackend {
while let RenderBackendStatus::Continue = status {
status = match self.api_rx.recv() {
Ok(msg) => {
self.process_api_msg(msg, &mut profile_counters, &mut frame_counter)
self.process_api_msg(msg, &mut frame_counter)
}
Err(..) => { RenderBackendStatus::ShutDown(None) }
};
@ -926,36 +933,21 @@ impl RenderBackend {
mut txns: Vec<Box<BuiltTransaction>>,
result_tx: Option<Sender<SceneSwapResult>>,
frame_counter: &mut u32,
profile_counters: &mut BackendProfileCounters,
) -> bool {
self.prepare_for_frames();
self.maybe_force_nop_documents(
frame_counter,
profile_counters,
|document_id| txns.iter().any(|txn| txn.document_id == document_id));
let mut built_frame = false;
for mut txn in txns.drain(..) {
let has_built_scene = txn.built_scene.is_some();
if let Some(timings) = txn.timings {
if has_built_scene {
profile_counters.scene_changed = true;
}
profile_counters.txn.set(
timings.builder_start_time_ns,
timings.builder_end_time_ns,
timings.send_time_ns,
timings.scene_build_start_time_ns,
timings.scene_build_end_time_ns,
timings.display_list_len,
);
}
if let Some(doc) = self.documents.get_mut(&txn.document_id) {
doc.removed_pipelines.append(&mut txn.removed_pipelines);
doc.view.scene = txn.view;
doc.profile.merge(&mut txn.profile);
if let Some(built_scene) = txn.built_scene.take() {
doc.new_async_scene_ready(
@ -976,7 +968,7 @@ impl RenderBackend {
self.tile_cache_logger.serialize_updates(&updates);
}
}
doc.data_stores.apply_updates(updates, profile_counters);
doc.data_stores.apply_updates(updates, &mut doc.profile);
}
// Build the hit tester while the APZ lock is held so that its content
@ -1000,6 +992,12 @@ impl RenderBackend {
.spatial_tree
.discard_frame_state_for_pipeline(*pipeline_id);
}
self.resource_cache.add_rasterized_blob_images(
txn.rasterized_blobs.take(),
&mut doc.profile,
);
} else {
// The document was removed while we were building it, skip it.
// TODO: we might want to just ensure that removed documents are
@ -1010,11 +1008,6 @@ impl RenderBackend {
continue;
}
self.resource_cache.add_rasterized_blob_images(
txn.rasterized_blobs.take(),
&mut profile_counters.resources.texture_cache,
);
built_frame |= self.update_document(
txn.document_id,
txn.resource_updates.take(),
@ -1023,7 +1016,6 @@ impl RenderBackend {
txn.render_frame,
txn.invalidate_rendered_frame,
frame_counter,
profile_counters,
has_built_scene,
);
}
@ -1034,7 +1026,6 @@ impl RenderBackend {
fn process_api_msg(
&mut self,
msg: ApiMsg,
profile_counters: &mut BackendProfileCounters,
frame_counter: &mut u32,
) -> RenderBackendStatus {
match msg {
@ -1115,7 +1106,7 @@ impl RenderBackend {
}
#[cfg(feature = "capture")]
DebugCommand::SaveCapture(root, bits) => {
let output = self.save_capture(root, bits, profile_counters);
let output = self.save_capture(root, bits);
ResultMsg::DebugOutput(output)
},
#[cfg(feature = "capture")]
@ -1139,7 +1130,7 @@ impl RenderBackend {
config.frame_id = frame_id;
}
self.load_capture(config, profile_counters);
self.load_capture(config);
for (id, doc) in &self.documents {
let captured = CapturedDocument {
@ -1230,11 +1221,10 @@ impl RenderBackend {
self.prepare_transactions(
transaction_msgs,
frame_counter,
profile_counters,
);
}
ApiMsg::SceneBuilderResult(msg) => {
return self.process_scene_builder_result(msg, profile_counters, frame_counter);
return self.process_scene_builder_result(msg, frame_counter);
}
}
@ -1244,7 +1234,6 @@ impl RenderBackend {
fn process_scene_builder_result(
&mut self,
msg: SceneBuilderResult,
profile_counters: &mut BackendProfileCounters,
frame_counter: &mut u32,
) -> RenderBackendStatus {
profile_scope!("sb_msg");
@ -1255,7 +1244,6 @@ impl RenderBackend {
txns,
result_tx,
frame_counter,
profile_counters,
);
self.bookkeep_after_frames();
},
@ -1275,7 +1263,6 @@ impl RenderBackend {
txns,
result_tx,
frame_counter,
profile_counters,
);
if built_frame {
@ -1357,16 +1344,20 @@ impl RenderBackend {
&mut self,
txns: Vec<Box<TransactionMsg>>,
frame_counter: &mut u32,
profile_counters: &mut BackendProfileCounters,
) {
self.prepare_for_frames();
self.maybe_force_nop_documents(
frame_counter,
profile_counters,
|document_id| txns.iter().any(|txn| txn.document_id == document_id));
let mut built_frame = false;
for mut txn in txns {
if txn.generate_frame {
txn.profile.end_time(profiler::API_SEND_TIME);
}
self.documents.get_mut(&txn.document_id).unwrap().profile.merge(&mut txn.profile);
built_frame |= self.update_document(
txn.document_id,
txn.resource_updates.take(),
@ -1375,7 +1366,6 @@ impl RenderBackend {
txn.generate_frame,
txn.invalidate_rendered_frame,
frame_counter,
profile_counters,
false
);
}
@ -1394,7 +1384,6 @@ impl RenderBackend {
/// to force a frame build.
fn maybe_force_nop_documents<F>(&mut self,
frame_counter: &mut u32,
profile_counters: &mut BackendProfileCounters,
document_already_present: F) where
F: Fn(DocumentId) -> bool {
if self.requires_frame_build() {
@ -1413,7 +1402,6 @@ impl RenderBackend {
false,
false,
frame_counter,
profile_counters,
false);
}
#[cfg(feature = "capture")]
@ -1433,13 +1421,13 @@ impl RenderBackend {
mut render_frame: bool,
invalidate_rendered_frame: bool,
frame_counter: &mut u32,
profile_counters: &mut BackendProfileCounters,
has_built_scene: bool,
) -> bool {
let requested_frame = render_frame;
let requires_frame_build = self.requires_frame_build();
let doc = self.documents.get_mut(&document_id).unwrap();
// If we have a sampler, get more frame ops from it and add them
// to the transaction. This is a hook to allow the WR user code to
// fiddle with things after a potentially long scene build, but just
@ -1458,7 +1446,6 @@ impl RenderBackend {
// for something wrench specific and we should remove it.
let mut scroll = false;
for frame_msg in frame_ops {
let _timer = profile_counters.total_time.timer();
let op = doc.process_frame_msg(frame_msg);
scroll |= op.scroll;
}
@ -1471,7 +1458,7 @@ impl RenderBackend {
self.resource_cache.post_scene_building_update(
resource_updates,
&mut profile_counters.resources,
&mut doc.profile,
);
if doc.dynamic_properties.flush_pending_updates() {
@ -1517,13 +1504,11 @@ impl RenderBackend {
// borrow ck hack for profile_counters
let (pending_update, rendered_document) = {
let _timer = profile_counters.total_time.timer();
let frame_build_start_time = precise_time_ns();
let rendered_document = doc.build_frame(
&mut self.resource_cache,
&mut self.gpu_cache,
&mut profile_counters.resources,
self.debug_flags,
&mut self.tile_cache_logger,
&mut self.tile_caches,
@ -1586,10 +1571,8 @@ impl RenderBackend {
document_id,
rendered_document,
pending_update,
profile_counters.clone()
);
self.result_tx.send(msg).unwrap();
profile_counters.reset();
} else if requested_frame {
// WR-internal optimization to avoid doing a bunch of render work if
// there's no pixels. We still want to pretend to render and request
@ -1712,7 +1695,6 @@ impl RenderBackend {
&mut self,
root: PathBuf,
bits: CaptureBits,
profile_counters: &mut BackendProfileCounters,
) -> DebugOutput {
use std::fs;
use crate::render_task_graph::dump_render_tasks_as_svg;
@ -1735,7 +1717,6 @@ impl RenderBackend {
let rendered_document = doc.build_frame(
&mut self.resource_cache,
&mut self.gpu_cache,
&mut profile_counters.resources,
self.debug_flags,
&mut self.tile_cache_logger,
&mut self.tile_caches,
@ -1851,7 +1832,6 @@ impl RenderBackend {
fn load_capture(
&mut self,
mut config: CaptureConfig,
profile_counters: &mut BackendProfileCounters,
) {
debug!("capture: loading {:?}", config.frame_root());
let backend = config.deserialize_for_frame::<PlainRenderBackend, _>("backend")
@ -1962,6 +1942,7 @@ impl RenderBackend {
loaded_scene: scene.clone(),
prev_composite_descriptor: CompositeDescriptor::empty(),
dirty_rects_are_valid: false,
profile: TransactionProfile::new(),
};
entry.insert(doc);
}
@ -1978,12 +1959,10 @@ impl RenderBackend {
let msg_publish = ResultMsg::PublishDocument(
id,
RenderedDocument { frame, is_new_scene: true },
RenderedDocument { frame, is_new_scene: true, profile: TransactionProfile::new() },
self.resource_cache.pending_updates(),
profile_counters.clone(),
);
self.result_tx.send(msg_publish).unwrap();
profile_counters.reset();
self.notifier.new_frame_ready(id, false, true, None);

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -26,7 +26,7 @@ use crate::glyph_rasterizer::{GLYPH_FLASHING, FontInstance, GlyphFormat, GlyphKe
use crate::gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle};
use crate::gpu_types::UvRectKind;
use crate::internal_types::{FastHashMap, FastHashSet, TextureSource, ResourceUpdateList};
use crate::profiler::{ResourceProfileCounters, TextureCacheProfileCounters};
use crate::profiler::{self, TransactionProfile, bytes_to_mb};
use crate::render_backend::{FrameId, FrameStamp};
use crate::render_task_graph::{RenderTaskGraph, RenderTaskId};
use crate::render_task_cache::{RenderTaskCache, RenderTaskCacheKey};
@ -461,6 +461,9 @@ pub struct ResourceCache {
/// A list of queued compositor surface updates to apply next frame.
pending_native_surface_updates: Vec<NativeSurfaceOperation>,
image_templates_memory: usize,
font_templates_memory: usize,
}
impl ResourceCache {
@ -492,6 +495,8 @@ impl ResourceCache {
pending_native_surface_updates: Vec::new(),
#[cfg(feature = "capture")]
capture_dirty: true,
image_templates_memory: 0,
font_templates_memory: 0,
}
}
@ -546,7 +551,7 @@ impl ResourceCache {
pub fn post_scene_building_update(
&mut self,
updates: Vec<ResourceUpdate>,
profile_counters: &mut ResourceProfileCounters,
profile: &mut TransactionProfile,
) {
// TODO, there is potential for optimization here, by processing updates in
// bulk rather than one by one (for example by sorting allocations by size or
@ -561,7 +566,8 @@ impl ResourceCache {
match update {
ResourceUpdate::AddImage(img) => {
if let ImageData::Raw(ref bytes) = img.data {
profile_counters.image_templates.inc(bytes.len());
self.image_templates_memory += bytes.len();
profile.set(profiler::IMAGE_TEMPLATES_MEM, bytes_to_mb(self.image_templates_memory));
}
self.add_image_template(
img.key,
@ -570,6 +576,7 @@ impl ResourceCache {
&img.descriptor.size.into(),
img.tiling,
);
profile.set(profiler::IMAGE_TEMPLATES, self.resources.image_templates.images.len());
}
ResourceUpdate::UpdateImage(img) => {
self.update_image_template(img.key, img.descriptor, img.data.into(), &img.dirty_rect);
@ -597,12 +604,16 @@ impl ResourceCache {
}
ResourceUpdate::DeleteImage(img) => {
self.delete_image_template(img);
profile.set(profiler::IMAGE_TEMPLATES, self.resources.image_templates.images.len());
profile.set(profiler::IMAGE_TEMPLATES_MEM, bytes_to_mb(self.image_templates_memory));
}
ResourceUpdate::DeleteBlobImage(img) => {
self.delete_image_template(img.as_image());
}
ResourceUpdate::DeleteFont(font) => {
self.delete_font_template(font);
profile.set(profiler::FONT_TEMPLATES, self.resources.font_templates.len());
profile.set(profiler::FONT_TEMPLATES_MEM, bytes_to_mb(self.font_templates_memory));
}
ResourceUpdate::DeleteFontInstance(font) => {
self.delete_font_instance(font);
@ -614,13 +625,15 @@ impl ResourceCache {
ResourceUpdate::AddFont(font) => {
match font {
AddFont::Raw(id, bytes, index) => {
profile_counters.font_templates.inc(bytes.len());
self.font_templates_memory += bytes.len();
profile.set(profiler::FONT_TEMPLATES_MEM, bytes_to_mb(self.font_templates_memory));
self.add_font_template(id, FontTemplate::Raw(bytes, index));
}
AddFont::Native(id, native_font_handle) => {
self.add_font_template(id, FontTemplate::Native(native_font_handle));
}
}
profile.set(profiler::FONT_TEMPLATES, self.resources.font_templates.len());
}
ResourceUpdate::AddFontInstance(..) => {
// Already added in ApiResources.
@ -632,7 +645,7 @@ impl ResourceCache {
pub fn add_rasterized_blob_images(
&mut self,
images: Vec<(BlobImageRequest, BlobImageResult)>,
texture_cache_profile: &mut TextureCacheProfileCounters,
profile: &mut TransactionProfile,
) {
for (request, result) in images {
let data = match result {
@ -643,7 +656,7 @@ impl ResourceCache {
}
};
texture_cache_profile.rasterized_blob_pixels.inc(data.rasterized_rect.area() as usize);
profile.add(profiler::RASTERIZED_BLOBS_PX, data.rasterized_rect.area());
// First make sure we have an entry for this key (using a placeholder
// if need be).
@ -680,7 +693,9 @@ impl ResourceCache {
pub fn delete_font_template(&mut self, font_key: FontKey) {
self.glyph_rasterizer.delete_font(font_key);
self.resources.font_templates.remove(&font_key);
if let Some(FontTemplate::Raw(data, _)) = self.resources.font_templates.remove(&font_key) {
self.font_templates_memory -= data.len();
}
self.cached_glyphs
.clear_fonts(|font| font.font_key == font_key);
}
@ -800,6 +815,10 @@ impl ResourceCache {
match value {
Some(image) => if image.data.is_blob() {
if let CachedImageData::Raw(data) = image.data {
self.image_templates_memory -= data.len();
}
let blob_key = BlobImageKey(image_key);
self.deleted_blob_keys.back_mut().unwrap().push(blob_key);
self.rasterized_blob_images.remove(&blob_key);
@ -1150,7 +1169,7 @@ impl ResourceCache {
&mut self,
gpu_cache: &mut GpuCache,
render_tasks: &mut RenderTaskGraph,
texture_cache_profile: &mut TextureCacheProfileCounters,
profile: &mut TransactionProfile,
) {
profile_scope!("block_until_all_resources_added");
@ -1163,7 +1182,7 @@ impl ResourceCache {
gpu_cache,
&mut self.cached_render_tasks,
render_tasks,
texture_cache_profile,
profile,
);
// Apply any updates of new / updated images (incl. blobs) to the texture cache.
@ -1384,11 +1403,11 @@ impl ResourceCache {
}
pub fn end_frame(&mut self, texture_cache_profile: &mut TextureCacheProfileCounters) {
pub fn end_frame(&mut self, profile: &mut TransactionProfile) {
debug_assert_eq!(self.state, State::QueryResources);
profile_scope!("end_frame");
self.state = State::Idle;
self.texture_cache.end_frame(texture_cache_profile);
self.texture_cache.end_frame(profile);
}
pub fn set_debug_flags(&mut self, flags: DebugFlags) {

Просмотреть файл

@ -26,6 +26,7 @@ use crate::prim_store::image::{Image, YuvImage};
use crate::prim_store::line_dec::LineDecoration;
use crate::prim_store::picture::Picture;
use crate::prim_store::text_run::TextRun;
use crate::profiler::{self, TransactionProfile};
use crate::render_backend::SceneView;
use crate::renderer::{PipelineInfo, SceneBuilderHooks};
use crate::scene::{Scene, BuiltScene, SceneStats};
@ -41,19 +42,6 @@ use crate::debug_server;
#[cfg(feature = "debugger")]
use api::{BuiltDisplayListIter, DisplayItem};
/// Various timing information that will be turned into
/// TransactionProfileCounters later down the pipeline.
#[derive(Clone, Debug)]
pub struct TransactionTimings {
pub builder_start_time_ns: u64,
pub builder_end_time_ns: u64,
pub send_time_ns: u64,
pub scene_build_start_time_ns: u64,
pub scene_build_end_time_ns: u64,
pub blob_rasterization_end_time_ns: u64,
pub display_list_len: usize,
}
fn rasterize_blobs(txn: &mut TransactionMsg, is_low_priority: bool) {
profile_scope!("rasterize_blobs");
@ -81,12 +69,10 @@ pub struct BuiltTransaction {
pub removed_pipelines: Vec<(PipelineId, DocumentId)>,
pub notifications: Vec<NotificationRequest>,
pub interner_updates: Option<InternerUpdates>,
pub scene_build_start_time: u64,
pub scene_build_end_time: u64,
pub render_frame: bool,
pub invalidate_rendered_frame: bool,
pub discard_frame_state_for_pipelines: Vec<PipelineId>,
pub timings: Option<TransactionTimings>,
pub profile: TransactionProfile,
}
#[cfg(feature = "replay")]
@ -427,8 +413,6 @@ impl SceneBuilderThread {
for mut item in scenes {
self.config = item.config;
let scene_build_start_time = precise_time_ns();
let mut built_scene = None;
let mut interner_updates = None;
@ -470,10 +454,8 @@ impl SceneBuilderThread {
removed_pipelines: Vec::new(),
discard_frame_state_for_pipelines: Vec::new(),
notifications: Vec::new(),
scene_build_start_time,
scene_build_end_time: precise_time_ns(),
interner_updates,
timings: None,
profile: TransactionProfile::new(),
})];
self.forward_built_transactions(txns);
@ -580,12 +562,12 @@ impl SceneBuilderThread {
hooks.pre_scene_build();
}
let scene_build_start_time = precise_time_ns();
let doc = self.documents.get_mut(&txn.document_id).unwrap();
let scene = &mut doc.scene;
let mut timings = None;
let mut profile = txn.profile.take();
profile.start_time(profiler::SCENE_BUILD_TIME);
let mut discard_frame_state_for_pipelines = Vec::new();
let mut removed_pipelines = Vec::new();
@ -613,11 +595,15 @@ impl SceneBuilderThread {
display_list,
preserve_frame_state,
} => {
let display_list_len = display_list.data().len();
let (builder_start_time_ns, builder_end_time_ns, send_time_ns) =
display_list.times();
let content_send_time = profiler::ns_to_ms(precise_time_ns() - send_time_ns);
let dl_build_time = profiler::ns_to_ms(builder_end_time_ns - builder_start_time_ns);
profile.set(profiler::CONTENT_SEND_TIME, content_send_time);
profile.set(profiler::DISPLAY_LIST_BUILD_TIME, dl_build_time);
profile.set(profiler::DISPLAY_LIST_MEM, profiler::bytes_to_mb(display_list.data().len()));
if self.removed_pipelines.contains(&pipeline_id) {
continue;
}
@ -635,16 +621,6 @@ impl SceneBuilderThread {
viewport_size,
);
timings = Some(TransactionTimings {
builder_start_time_ns,
builder_end_time_ns,
send_time_ns,
scene_build_start_time_ns: 0,
scene_build_end_time_ns: 0,
blob_rasterization_end_time_ns: 0,
display_list_len,
});
if !preserve_frame_state {
discard_frame_state_for_pipelines.push(pipeline_id);
}
@ -689,15 +665,16 @@ impl SceneBuilderThread {
built_scene = Some(built);
}
let scene_build_end_time = precise_time_ns();
profile.end_time(profiler::SCENE_BUILD_TIME);
let is_low_priority = false;
rasterize_blobs(txn, is_low_priority);
if let Some(timings) = timings.as_mut() {
timings.blob_rasterization_end_time_ns = precise_time_ns();
timings.scene_build_start_time_ns = scene_build_start_time;
timings.scene_build_end_time_ns = scene_build_end_time;
if !txn.blob_requests.is_empty() {
profile.start_time(profiler::BLOB_RASTERIZATION_TIME);
let is_low_priority = false;
rasterize_blobs(txn, is_low_priority);
profile.end_time(profiler::BLOB_RASTERIZATION_TIME);
}
drain_filter(
@ -724,9 +701,7 @@ impl SceneBuilderThread {
discard_frame_state_for_pipelines,
notifications: replace(&mut txn.notifications, Vec::new()),
interner_updates,
scene_build_start_time,
scene_build_end_time,
timings,
profile,
})
}
@ -751,7 +726,7 @@ impl SceneBuilderThread {
let (tx, rx) = single_msg_channel();
let txn = txns.iter().find(|txn| txn.built_scene.is_some()).unwrap();
hooks.pre_scene_swap(txn.scene_build_end_time - txn.scene_build_start_time);
hooks.pre_scene_swap((txn.profile.get(profiler::SCENE_BUILD_TIME).unwrap() * 1000000.0) as u64);
(Some(info), Some(tx), Some(rx))
} else {

Просмотреть файл

@ -17,7 +17,7 @@ use crate::internal_types::{
TextureCacheAllocInfo, TextureCacheUpdate,
};
use crate::lru_cache::LRUCache;
use crate::profiler::{ResourceProfileCounter, TextureCacheProfileCounters};
use crate::profiler::{self, TransactionProfile};
use crate::render_backend::FrameStamp;
use crate::resource_cache::{CacheItem, CachedImageData};
use smallvec::SmallVec;
@ -376,7 +376,7 @@ impl PictureTextures {
}
}
fn update_profile(&self, profile: &mut ResourceProfileCounter) {
fn update_profile(&self, profile: &mut TransactionProfile) {
// For now, this profile counter just accumulates the slices and bytes
// from all picture cache texture arrays.
let mut picture_slices = 0;
@ -385,7 +385,8 @@ impl PictureTextures {
picture_slices += texture.slices.len();
picture_bytes += texture.size_in_bytes();
}
profile.set(picture_slices, picture_bytes);
profile.set(profiler::PICTURE_TILES, picture_slices);
profile.set(profiler::PICTURE_TILES_MEM, profiler::bytes_to_mb(picture_bytes));
}
}
@ -615,7 +616,7 @@ impl TextureCache {
self.evict_items_from_cache_if_required();
}
pub fn end_frame(&mut self, texture_cache_profile: &mut TextureCacheProfileCounters) {
pub fn end_frame(&mut self, profile: &mut TransactionProfile) {
debug_assert!(self.now.is_valid());
self.expire_old_picture_cache_tiles();
@ -627,18 +628,30 @@ impl TextureCache {
self.shared_textures.array_color8_linear.release_empty_textures(&mut self.pending_updates);
self.shared_textures.array_color8_nearest.release_empty_textures(&mut self.pending_updates);
self.shared_textures.array_alpha8_linear
.update_profile(&mut texture_cache_profile.pages_alpha8_linear);
self.shared_textures.array_alpha16_linear
.update_profile(&mut texture_cache_profile.pages_alpha16_linear);
self.shared_textures.array_color8_linear
.update_profile(&mut texture_cache_profile.pages_color8_linear);
self.shared_textures.array_color8_nearest
.update_profile(&mut texture_cache_profile.pages_color8_nearest);
self.picture_textures
.update_profile(&mut texture_cache_profile.pages_picture);
texture_cache_profile.shared_bytes.set(self.shared_bytes_allocated);
texture_cache_profile.standalone_bytes.set(self.standalone_bytes_allocated);
self.shared_textures.array_alpha8_linear.update_profile(
profiler::TEXTURE_CACHE_A8_REGIONS,
profiler::TEXTURE_CACHE_A8_MEM,
profile,
);
self.shared_textures.array_alpha16_linear.update_profile(
profiler::TEXTURE_CACHE_A16_REGIONS,
profiler::TEXTURE_CACHE_A16_MEM,
profile,
);
self.shared_textures.array_color8_linear.update_profile(
profiler::TEXTURE_CACHE_RGBA8_LINEAR_REGIONS,
profiler::TEXTURE_CACHE_RGBA8_LINEAR_MEM,
profile,
);
self.shared_textures.array_color8_nearest.update_profile(
profiler::TEXTURE_CACHE_RGBA8_NEAREST_REGIONS,
profiler::TEXTURE_CACHE_RGBA8_NEAREST_MEM,
profile,
);
self.picture_textures.update_profile(profile);
profile.set(profiler::TEXTURE_CACHE_SHARED_MEM, self.shared_bytes_allocated);
profile.set(profiler::TEXTURE_CACHE_STANDALONE_MEM, self.standalone_bytes_allocated);
self.now = FrameStamp::INVALID;
}
@ -1461,9 +1474,10 @@ impl TextureArray {
});
}
fn update_profile(&self, counter: &mut ResourceProfileCounter) {
fn update_profile(&self, count_idx: usize, mem_idx: usize, profile: &mut TransactionProfile) {
let num_regions: usize = self.units.iter().map(|u| u.regions.len()).sum();
counter.set(num_regions, self.size_in_bytes());
profile.set(count_idx, num_regions);
profile.set(mem_idx, profiler::bytes_to_mb(self.size_in_bytes()));
}
/// Allocate space in this texture array.

Просмотреть файл

@ -513,57 +513,48 @@ bitflags! {
const DISABLE_BATCHING = 1 << 5;
/// Display the pipeline epochs.
const EPOCHS = 1 << 6;
/// Reduce the amount of information displayed by the profiler so that
/// it occupies less screen real-estate.
const COMPACT_PROFILER = 1 << 7;
/// Print driver messages to stdout.
const ECHO_DRIVER_MESSAGES = 1 << 8;
/// Show an indicator that moves every time a frame is rendered.
const NEW_FRAME_INDICATOR = 1 << 9;
/// Show an indicator that moves every time a scene is built.
const NEW_SCENE_INDICATOR = 1 << 10;
const ECHO_DRIVER_MESSAGES = 1 << 7;
/// Show an overlay displaying overdraw amount.
const SHOW_OVERDRAW = 1 << 11;
const SHOW_OVERDRAW = 1 << 8;
/// Display the contents of GPU cache.
const GPU_CACHE_DBG = 1 << 12;
/// Show a red bar that moves each time a slow frame is detected.
const SLOW_FRAME_INDICATOR = 1 << 13;
const GPU_CACHE_DBG = 1 << 9;
/// Clear evicted parts of the texture cache for debugging purposes.
const TEXTURE_CACHE_DBG_CLEAR_EVICTED = 1 << 14;
const TEXTURE_CACHE_DBG_CLEAR_EVICTED = 1 << 10;
/// Show picture caching debug overlay
const PICTURE_CACHING_DBG = 1 << 15;
const PICTURE_CACHING_DBG = 1 << 11;
/// Highlight all primitives with colors based on kind.
const PRIMITIVE_DBG = 1 << 16;
const PRIMITIVE_DBG = 1 << 12;
/// Draw a zoom widget showing part of the framebuffer zoomed in.
const ZOOM_DBG = 1 << 17;
const ZOOM_DBG = 1 << 13;
/// Scale the debug renderer down for a smaller screen. This will disrupt
/// any mapping between debug display items and page content, so shouldn't
/// be used with overlays like the picture caching or primitive display.
const SMALL_SCREEN = 1 << 18;
const SMALL_SCREEN = 1 << 14;
/// Disable various bits of the WebRender pipeline, to help narrow
/// down where slowness might be coming from.
const DISABLE_OPAQUE_PASS = 1 << 19;
const DISABLE_OPAQUE_PASS = 1 << 15;
///
const DISABLE_ALPHA_PASS = 1 << 20;
const DISABLE_ALPHA_PASS = 1 << 16;
///
const DISABLE_CLIP_MASKS = 1 << 21;
const DISABLE_CLIP_MASKS = 1 << 17;
///
const DISABLE_TEXT_PRIMS = 1 << 22;
const DISABLE_TEXT_PRIMS = 1 << 18;
///
const DISABLE_GRADIENT_PRIMS = 1 << 23;
const DISABLE_GRADIENT_PRIMS = 1 << 19;
///
const OBSCURE_IMAGES = 1 << 24;
const OBSCURE_IMAGES = 1 << 20;
/// Taint the transparent area of the glyphs with a random opacity to easily
/// see when glyphs are re-rasterized.
const GLYPH_FLASHING = 1 << 25;
const GLYPH_FLASHING = 1 << 21;
/// The profiler only displays information that is out of the ordinary.
const SMART_PROFILER = 1 << 26;
const SMART_PROFILER = 1 << 22;
/// If set, dump picture cache invalidation debug to console.
const INVALIDATION_DBG = 1 << 27;
const INVALIDATION_DBG = 1 << 23;
/// Log tile cache to memory for later saving as part of wr-capture
const TILE_CACHE_LOGGING_DBG = 1 << 28;
const TILE_CACHE_LOGGING_DBG = 1 << 24;
/// Collect and dump profiler statistics to captures.
const PROFILER_CAPTURE = (1 as u32) << 31; // need "as u32" until we have cbindgen#556
const PROFILER_CAPTURE = (1 as u32) << 25; // need "as u32" until we have cbindgen#556
}
}

Просмотреть файл

@ -80,6 +80,10 @@ args:
- no_block:
long: no-block
help: Don't block on UI events - run event loop as fast as possible.
- profiler_ui:
long: profiler-ui
takes_value: true
help: A string describing what to show on in the profiler HUD (See https://github.com/servo/webrender/wiki/Debugging-WebRender#anchor_6).
subcommands:
- png:

Просмотреть файл

@ -666,6 +666,11 @@ fn main() {
dump_shader_source,
notifier,
);
if let Some(ui_str) = args.value_of("profiler_ui") {
wrench.renderer.set_profiler_ui(&ui_str);
}
window.update(&mut wrench);
if let Some(window_title) = wrench.take_title() {
@ -802,7 +807,7 @@ fn render<'a>(
// Default the profile overlay on for android.
if cfg!(target_os = "android") {
debug_flags.toggle(DebugFlags::PROFILER_DBG | DebugFlags::COMPACT_PROFILER);
debug_flags.toggle(DebugFlags::PROFILER_DBG);
wrench.api.send_debug_cmd(DebugCommand::SetFlags(debug_flags));
}
@ -864,11 +869,6 @@ fn render<'a>(
wrench.api.send_debug_cmd(DebugCommand::SetFlags(debug_flags));
do_render = true;
}
VirtualKeyCode::S => {
debug_flags.toggle(DebugFlags::COMPACT_PROFILER);
wrench.api.send_debug_cmd(DebugCommand::SetFlags(debug_flags));
do_render = true;
}
VirtualKeyCode::D => {
debug_flags.toggle(DebugFlags::PICTURE_CACHING_DBG);
wrench.api.send_debug_cmd(DebugCommand::SetFlags(debug_flags));

Просмотреть файл

@ -665,11 +665,7 @@ pref("gfx.webrender.debug.gpu-time-queries", false);
pref("gfx.webrender.debug.gpu-sample-queries", false);
pref("gfx.webrender.debug.disable-batching", false);
pref("gfx.webrender.debug.epochs", false);
pref("gfx.webrender.debug.compact-profiler", false);
pref("gfx.webrender.debug.smart-profiler", false);
pref("gfx.webrender.debug.echo-driver-messages", false);
pref("gfx.webrender.debug.new-frame-indicator", false);
pref("gfx.webrender.debug.new-scene-indicator", false);
pref("gfx.webrender.debug.show-overdraw", false);
pref("gfx.webrender.debug.slow-frame-indicator", false);
pref("gfx.webrender.debug.picture-caching", false);
@ -679,6 +675,7 @@ pref("gfx.webrender.debug.small-screen", false);
pref("gfx.webrender.debug.obscure-images", false);
pref("gfx.webrender.debug.glyph-flashing", false);
pref("gfx.webrender.debug.capture-profiler", false);
pref("gfx.webrender.debug.profiler-ui", "Default");
pref("accessibility.warn_on_browsewithcaret", true);