CompositorBench.cpp (10859B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "CompositorBench.h" 8 9 #ifdef MOZ_COMPOSITOR_BENCH 10 # include "mozilla/gfx/2D.h" 11 # include "mozilla/layers/Compositor.h" 12 # include "mozilla/layers/Effects.h" 13 # include "mozilla/ProfilerMarkers.h" 14 # include "mozilla/StaticPrefs_layers.h" 15 # include "mozilla/TimeStamp.h" 16 # include <math.h> 17 18 # define TEST_STEPS 1000 19 # define DURATION_THRESHOLD 30 20 # define THRESHOLD_ABORT_COUNT 5 21 22 namespace mozilla { 23 namespace layers { 24 25 using namespace mozilla::gfx; 26 27 static float SimplePseudoRandom(int aStep, int aCount) { 28 srand(aStep * 1000 + aCount); 29 return static_cast<float>(rand()) / static_cast<float>(RAND_MAX); 30 } 31 32 class BenchTest { 33 public: 34 BenchTest(const char* aTestName) : mTestName(aTestName) {} 35 36 virtual ~BenchTest() = default; 37 38 virtual void Setup(Compositor* aCompositor, size_t aStep) {} 39 virtual void Teardown(Compositor* aCompositor) {} 40 virtual void DrawFrame(Compositor* aCompositor, const gfx::Rect& aScreenRect, 41 size_t aStep) = 0; 42 43 const char* ToString() { return mTestName; } 44 45 private: 46 const char* mTestName; 47 }; 48 49 static void DrawFrameTrivialQuad(Compositor* aCompositor, 50 const gfx::Rect& aScreenRect, size_t aStep, 51 const EffectChain& effects) { 52 for (size_t i = 0; i < aStep * 10; i++) { 53 const gfx::Rect& rect = gfx::Rect(i % (int)aScreenRect.width, 54 (int)(i / aScreenRect.height), 1, 1); 55 const gfx::Rect& clipRect = aScreenRect; 56 57 float opacity = 1.f; 58 59 gfx::Matrix transform2d; 60 61 gfx::Matrix4x4 transform = gfx::Matrix4x4::From2D(transform2d); 62 63 aCompositor->DrawQuad(rect, clipRect, effects, opacity, transform); 64 } 65 } 66 67 static void DrawFrameStressQuad(Compositor* aCompositor, 68 const gfx::Rect& aScreenRect, size_t aStep, 69 const EffectChain& effects) { 70 for (size_t i = 0; i < aStep * 10; i++) { 71 const gfx::Rect& rect = 72 gfx::Rect(aScreenRect.width * SimplePseudoRandom(i, 0), 73 aScreenRect.height * SimplePseudoRandom(i, 1), 74 aScreenRect.width * SimplePseudoRandom(i, 2), 75 aScreenRect.height * SimplePseudoRandom(i, 3)); 76 const gfx::Rect& clipRect = aScreenRect; 77 78 float opacity = 1.f; 79 80 gfx::Matrix transform2d; 81 transform2d = transform2d.PreRotate(SimplePseudoRandom(i, 4) * 70.f); 82 83 gfx::Matrix4x4 transform = gfx::Matrix4x4::From2D(transform2d); 84 85 aCompositor->DrawQuad(rect, clipRect, effects, opacity, transform); 86 } 87 } 88 89 class EffectSolidColorBench : public BenchTest { 90 public: 91 EffectSolidColorBench() 92 : BenchTest("EffectSolidColorBench (clear frame with EffectSolidColor)") { 93 } 94 95 void DrawFrame(Compositor* aCompositor, const gfx::Rect& aScreenRect, 96 size_t aStep) { 97 float tmp; 98 float red = modff(aStep * 0.03f, &tmp); 99 EffectChain effects; 100 effects.mPrimaryEffect = 101 new EffectSolidColor(gfx::DeviceColor(red, 0.4f, 0.4f, 1.0f)); 102 103 const gfx::Rect& rect = aScreenRect; 104 const gfx::Rect& clipRect = aScreenRect; 105 106 float opacity = 1.f; 107 108 gfx::Matrix4x4 transform; 109 aCompositor->DrawQuad(rect, clipRect, effects, opacity, transform); 110 } 111 }; 112 113 class EffectSolidColorTrivialBench : public BenchTest { 114 public: 115 EffectSolidColorTrivialBench() 116 : BenchTest("EffectSolidColorTrivialBench (10s 1x1 EffectSolidColor)") {} 117 118 void DrawFrame(Compositor* aCompositor, const gfx::Rect& aScreenRect, 119 size_t aStep) { 120 EffectChain effects; 121 effects.mPrimaryEffect = CreateEffect(aStep); 122 123 DrawFrameTrivialQuad(aCompositor, aScreenRect, aStep, effects); 124 } 125 126 already_AddRefed<Effect> CreateEffect(size_t i) { 127 float tmp; 128 float red = modff(i * 0.03f, &tmp); 129 EffectChain effects; 130 return MakeAndAddRef<EffectSolidColor>( 131 gfx::DeviceColor(red, 0.4f, 0.4f, 1.0f)); 132 } 133 }; 134 135 class EffectSolidColorStressBench : public BenchTest { 136 public: 137 EffectSolidColorStressBench() 138 : BenchTest( 139 "EffectSolidColorStressBench (10s various EffectSolidColor)") {} 140 141 void DrawFrame(Compositor* aCompositor, const gfx::Rect& aScreenRect, 142 size_t aStep) { 143 EffectChain effects; 144 effects.mPrimaryEffect = CreateEffect(aStep); 145 146 DrawFrameStressQuad(aCompositor, aScreenRect, aStep, effects); 147 } 148 149 already_AddRefed<Effect> CreateEffect(size_t i) { 150 float tmp; 151 float red = modff(i * 0.03f, &tmp); 152 EffectChain effects; 153 return MakeAndAddRef<EffectSolidColor>( 154 gfx::DeviceColor(red, 0.4f, 0.4f, 1.0f)); 155 } 156 }; 157 158 class UploadBench : public BenchTest { 159 public: 160 UploadBench() : BenchTest("Upload Bench (10s 256x256 upload)") {} 161 162 uint32_t* mBuf; 163 RefPtr<DataSourceSurface> mSurface; 164 RefPtr<DataTextureSource> mTexture; 165 166 virtual void Setup(Compositor* aCompositor, size_t aStep) { 167 int bytesPerPixel = 4; 168 int w = 256; 169 int h = 256; 170 mBuf = (uint32_t*)malloc(w * h * sizeof(uint32_t)); 171 172 mSurface = Factory::CreateWrappingDataSourceSurface( 173 reinterpret_cast<uint8_t*>(mBuf), w * bytesPerPixel, IntSize(w, h), 174 SurfaceFormat::B8G8R8A8); 175 mTexture = aCompositor->CreateDataTextureSource(); 176 } 177 178 virtual void Teardown(Compositor* aCompositor) { 179 mSurface = nullptr; 180 mTexture = nullptr; 181 free(mBuf); 182 } 183 184 void DrawFrame(Compositor* aCompositor, const gfx::Rect& aScreenRect, 185 size_t aStep) { 186 for (size_t i = 0; i < aStep * 10; i++) { 187 mTexture->Update(mSurface); 188 } 189 } 190 }; 191 192 class TrivialTexturedQuadBench : public BenchTest { 193 public: 194 TrivialTexturedQuadBench() 195 : BenchTest("Trvial Textured Quad (10s 256x256 quads)") {} 196 197 uint32_t* mBuf; 198 RefPtr<DataSourceSurface> mSurface; 199 RefPtr<DataTextureSource> mTexture; 200 201 virtual void Setup(Compositor* aCompositor, size_t aStep) { 202 int bytesPerPixel = 4; 203 size_t w = 256; 204 size_t h = 256; 205 mBuf = (uint32_t*)malloc(w * h * sizeof(uint32_t)); 206 for (size_t i = 0; i < w * h; i++) { 207 mBuf[i] = 0xFF00008F; 208 } 209 210 mSurface = Factory::CreateWrappingDataSourceSurface( 211 reinterpret_cast<uint8_t*>(mBuf), w * bytesPerPixel, IntSize(w, h), 212 SurfaceFormat::B8G8R8A8); 213 mTexture = aCompositor->CreateDataTextureSource(); 214 mTexture->Update(mSurface); 215 } 216 217 void DrawFrame(Compositor* aCompositor, const gfx::Rect& aScreenRect, 218 size_t aStep) { 219 EffectChain effects; 220 effects.mPrimaryEffect = CreateEffect(aStep); 221 222 DrawFrameTrivialQuad(aCompositor, aScreenRect, aStep, effects); 223 } 224 225 virtual void Teardown(Compositor* aCompositor) { 226 mSurface = nullptr; 227 mTexture = nullptr; 228 free(mBuf); 229 } 230 231 already_AddRefed<Effect> CreateEffect(size_t i) { 232 return CreateTexturedEffect(SurfaceFormat::B8G8R8A8, mTexture, 233 SamplingFilter::POINT, true); 234 } 235 }; 236 237 class StressTexturedQuadBench : public BenchTest { 238 public: 239 StressTexturedQuadBench() 240 : BenchTest("Stress Textured Quad (10s 256x256 quads)") {} 241 242 uint32_t* mBuf; 243 RefPtr<DataSourceSurface> mSurface; 244 RefPtr<DataTextureSource> mTexture; 245 246 virtual void Setup(Compositor* aCompositor, size_t aStep) { 247 int bytesPerPixel = 4; 248 size_t w = 256; 249 size_t h = 256; 250 mBuf = (uint32_t*)malloc(w * h * sizeof(uint32_t)); 251 for (size_t i = 0; i < w * h; i++) { 252 mBuf[i] = 0xFF00008F; 253 } 254 255 mSurface = Factory::CreateWrappingDataSourceSurface( 256 reinterpret_cast<uint8_t*>(mBuf), w * bytesPerPixel, IntSize(w, h), 257 SurfaceFormat::B8G8R8A8); 258 mTexture = aCompositor->CreateDataTextureSource(); 259 mTexture->Update(mSurface); 260 } 261 262 void DrawFrame(Compositor* aCompositor, const gfx::Rect& aScreenRect, 263 size_t aStep) { 264 EffectChain effects; 265 effects.mPrimaryEffect = CreateEffect(aStep); 266 267 DrawFrameStressQuad(aCompositor, aScreenRect, aStep, effects); 268 } 269 270 virtual void Teardown(Compositor* aCompositor) { 271 mSurface = nullptr; 272 mTexture = nullptr; 273 free(mBuf); 274 } 275 276 virtual already_AddRefed<Effect> CreateEffect(size_t i) { 277 return CreateTexturedEffect(SurfaceFormat::B8G8R8A8, mTexture, 278 SamplingFilter::POINT, true); 279 } 280 }; 281 282 static void RunCompositorBench(Compositor* aCompositor, 283 const gfx::Rect& aScreenRect) { 284 std::vector<BenchTest*> tests; 285 286 tests.push_back(new EffectSolidColorBench()); 287 tests.push_back(new UploadBench()); 288 tests.push_back(new EffectSolidColorTrivialBench()); 289 tests.push_back(new EffectSolidColorStressBench()); 290 tests.push_back(new TrivialTexturedQuadBench()); 291 tests.push_back(new StressTexturedQuadBench()); 292 293 for (size_t i = 0; i < tests.size(); i++) { 294 BenchTest* test = tests[i]; 295 std::vector<TimeDuration> results; 296 int testsOverThreshold = 0; 297 PROFILER_MARKER_UNTYPED( 298 ProfilerString8View::WrapNullTerminatedString(test->ToString()), 299 GRAPHICS); 300 for (size_t j = 0; j < TEST_STEPS; j++) { 301 test->Setup(aCompositor, j); 302 303 TimeStamp start = TimeStamp::Now(); 304 IntRect screenRect(aScreenRect.x, aScreenRect.y, aScreenRect.width, 305 aScreenRect.height); 306 aCompositor->BeginFrame(IntRect(screenRect.x, screenRect.y, 307 screenRect.width, screenRect.height), 308 nullptr, aScreenRect, nullptr, nullptr); 309 310 test->DrawFrame(aCompositor, aScreenRect, j); 311 312 aCompositor->EndFrame(); 313 results.push_back(TimeStamp::Now() - start); 314 315 if (results[j].ToMilliseconds() > DURATION_THRESHOLD) { 316 testsOverThreshold++; 317 if (testsOverThreshold == THRESHOLD_ABORT_COUNT) { 318 test->Teardown(aCompositor); 319 break; 320 } 321 } else { 322 testsOverThreshold = 0; 323 } 324 test->Teardown(aCompositor); 325 } 326 327 printf_stderr("%s\n", test->ToString()); 328 printf_stderr("Run step, Time (ms)\n"); 329 for (size_t j = 0; j < results.size(); j++) { 330 printf_stderr("%i,%f\n", j, (float)results[j].ToMilliseconds()); 331 } 332 printf_stderr("\n", test->ToString()); 333 } 334 335 for (size_t i = 0; i < tests.size(); i++) { 336 delete tests[i]; 337 } 338 } 339 340 void CompositorBench(Compositor* aCompositor, const gfx::IntRect& aScreenRect) { 341 static bool sRanBenchmark = false; 342 bool wantBenchmark = StaticPrefs::layers_bench_enabled(); 343 if (wantBenchmark && !sRanBenchmark) { 344 RunCompositorBench(aCompositor, aScreenRect); 345 } 346 sRanBenchmark = wantBenchmark; 347 } 348 349 } // namespace layers 350 } // namespace mozilla 351 352 #endif