Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/webrender_bindings/RenderThread.cpp
Line
Count
Source (jump to first uncovered line)
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 "base/task.h"
8
#include "GeckoProfiler.h"
9
#include "RenderThread.h"
10
#include "nsThreadUtils.h"
11
#include "mtransport/runnable_utils.h"
12
#include "mozilla/layers/AsyncImagePipelineManager.h"
13
#include "mozilla/gfx/GPUParent.h"
14
#include "mozilla/layers/CompositorThread.h"
15
#include "mozilla/layers/CompositorBridgeParent.h"
16
#include "mozilla/layers/WebRenderBridgeParent.h"
17
#include "mozilla/layers/SharedSurfacesParent.h"
18
#include "mozilla/StaticPtr.h"
19
#include "mozilla/Telemetry.h"
20
#include "mozilla/webrender/RendererOGL.h"
21
#include "mozilla/webrender/RenderTextureHost.h"
22
#include "mozilla/widget/CompositorWidget.h"
23
24
#ifdef XP_WIN
25
#include "mozilla/widget/WinCompositorWindowThread.h"
26
#endif
27
28
namespace mozilla {
29
namespace wr {
30
31
static StaticRefPtr<RenderThread> sRenderThread;
32
33
RenderThread::RenderThread(base::Thread* aThread)
34
  : mThread(aThread)
35
  , mFrameCountMapLock("RenderThread.mFrameCountMapLock")
36
  , mRenderTextureMapLock("RenderThread.mRenderTextureMapLock")
37
  , mHasShutdown(false)
38
  , mHandlingDeviceReset(false)
39
0
{
40
0
41
0
}
42
43
RenderThread::~RenderThread()
44
0
{
45
0
  MOZ_ASSERT(mRenderTexturesDeferred.empty());
46
0
  delete mThread;
47
0
}
48
49
// static
50
RenderThread*
51
RenderThread::Get()
52
0
{
53
0
  return sRenderThread;
54
0
}
55
56
// static
57
void
58
RenderThread::Start()
59
0
{
60
0
  MOZ_ASSERT(NS_IsMainThread());
61
0
  MOZ_ASSERT(!sRenderThread);
62
0
63
0
  base::Thread* thread = new base::Thread("Renderer");
64
0
65
0
  base::Thread::Options options;
66
0
  // TODO(nical): The compositor thread has a bunch of specific options, see
67
0
  // which ones make sense here.
68
0
  if (!thread->StartWithOptions(options)) {
69
0
    delete thread;
70
0
    return;
71
0
  }
72
0
73
0
  sRenderThread = new RenderThread(thread);
74
#ifdef XP_WIN
75
  widget::WinCompositorWindowThread::Start();
76
#endif
77
  layers::SharedSurfacesParent::Initialize();
78
0
79
0
  if (XRE_IsGPUProcess() &&
80
0
      gfx::gfxVars::UseWebRenderProgramBinary()) {
81
0
    MOZ_ASSERT(gfx::gfxVars::UseWebRender());
82
0
    // Initialize program cache if necessary
83
0
    RefPtr<Runnable> runnable = WrapRunnable(
84
0
      RefPtr<RenderThread>(sRenderThread.get()),
85
0
      &RenderThread::ProgramCacheTask);
86
0
    sRenderThread->Loop()->PostTask(runnable.forget());
87
0
  }
88
0
}
89
90
// static
91
void
92
RenderThread::ShutDown()
93
0
{
94
0
  MOZ_ASSERT(NS_IsMainThread());
95
0
  MOZ_ASSERT(sRenderThread);
96
0
97
0
  {
98
0
    MutexAutoLock lock(sRenderThread->mRenderTextureMapLock);
99
0
    sRenderThread->mHasShutdown = true;
100
0
  }
101
0
102
0
  layers::SynchronousTask task("RenderThread");
103
0
  RefPtr<Runnable> runnable = WrapRunnable(
104
0
    RefPtr<RenderThread>(sRenderThread.get()),
105
0
    &RenderThread::ShutDownTask,
106
0
    &task);
107
0
  sRenderThread->Loop()->PostTask(runnable.forget());
108
0
  task.Wait();
109
0
110
0
  sRenderThread = nullptr;
111
#ifdef XP_WIN
112
  widget::WinCompositorWindowThread::ShutDown();
113
#endif
114
}
115
116
extern void ClearAllBlobImageResources();
117
118
void
119
RenderThread::ShutDownTask(layers::SynchronousTask* aTask)
120
0
{
121
0
  layers::AutoCompleteTask complete(aTask);
122
0
  MOZ_ASSERT(IsInRenderThread());
123
0
124
0
  // Releasing on the render thread will allow us to avoid dispatching to remove
125
0
  // remaining textures from the texture map.
126
0
  layers::SharedSurfacesParent::Shutdown();
127
0
128
0
  ClearAllBlobImageResources();
129
0
}
130
131
// static
132
MessageLoop*
133
RenderThread::Loop()
134
0
{
135
0
  return sRenderThread ? sRenderThread->mThread->message_loop() : nullptr;
136
0
}
137
138
// static
139
bool
140
RenderThread::IsInRenderThread()
141
0
{
142
0
  return sRenderThread && sRenderThread->mThread->thread_id() == PlatformThread::CurrentId();
143
0
}
144
145
void
146
RenderThread::DoAccumulateMemoryReport(MemoryReport aReport, const RefPtr<MemoryReportPromise::Private>& aPromise)
147
0
{
148
0
  MOZ_ASSERT(IsInRenderThread());
149
0
  for (auto& r: mRenderers) {
150
0
    wr_renderer_accumulate_memory_report(r.second->GetRenderer(), &aReport);
151
0
  }
152
0
153
0
  aPromise->Resolve(aReport, __func__);
154
0
}
155
156
// static
157
RefPtr<MemoryReportPromise>
158
RenderThread::AccumulateMemoryReport(MemoryReport aInitial)
159
0
{
160
0
  RefPtr<MemoryReportPromise::Private> p = new MemoryReportPromise::Private(__func__);
161
0
  MOZ_ASSERT(!IsInRenderThread());
162
0
  MOZ_ASSERT(Get());
163
0
  Get()->Loop()->PostTask(
164
0
    NewRunnableMethod<MemoryReport, RefPtr<MemoryReportPromise::Private>>(
165
0
      "wr::RenderThread::DoAccumulateMemoryReport",
166
0
      Get(),
167
0
      &RenderThread::DoAccumulateMemoryReport,
168
0
      aInitial, p
169
0
    )
170
0
  );
171
0
172
0
  return p;
173
0
}
174
175
void
176
RenderThread::AddRenderer(wr::WindowId aWindowId, UniquePtr<RendererOGL> aRenderer)
177
0
{
178
0
  MOZ_ASSERT(IsInRenderThread());
179
0
180
0
  if (mHasShutdown) {
181
0
    return;
182
0
  }
183
0
184
0
  mRenderers[aWindowId] = std::move(aRenderer);
185
0
186
0
  MutexAutoLock lock(mFrameCountMapLock);
187
0
  mWindowInfos.emplace(AsUint64(aWindowId), new WindowInfo());
188
0
}
189
190
void
191
RenderThread::RemoveRenderer(wr::WindowId aWindowId)
192
0
{
193
0
  MOZ_ASSERT(IsInRenderThread());
194
0
195
0
  if (mHasShutdown) {
196
0
    return;
197
0
  }
198
0
199
0
  mRenderers.erase(aWindowId);
200
0
201
0
  if (mRenderers.size() == 0 && mHandlingDeviceReset) {
202
0
    mHandlingDeviceReset = false;
203
0
  }
204
0
205
0
  MutexAutoLock lock(mFrameCountMapLock);
206
0
  auto it = mWindowInfos.find(AsUint64(aWindowId));
207
0
  MOZ_ASSERT(it != mWindowInfos.end());
208
0
  WindowInfo* toDelete = it->second;
209
0
  mWindowInfos.erase(it);
210
0
  delete toDelete;
211
0
}
212
213
RendererOGL*
214
RenderThread::GetRenderer(wr::WindowId aWindowId)
215
0
{
216
0
  MOZ_ASSERT(IsInRenderThread());
217
0
218
0
  auto it = mRenderers.find(aWindowId);
219
0
  MOZ_ASSERT(it != mRenderers.end());
220
0
221
0
  if (it == mRenderers.end()) {
222
0
    return nullptr;
223
0
  }
224
0
225
0
  return it->second.get();
226
0
}
227
228
size_t
229
RenderThread::RendererCount()
230
0
{
231
0
  MOZ_ASSERT(IsInRenderThread());
232
0
  return mRenderers.size();
233
0
}
234
235
void
236
RenderThread::NewFrameReady(wr::WindowId aWindowId)
237
0
{
238
0
  if (mHasShutdown) {
239
0
    return;
240
0
  }
241
0
242
0
  if (!IsInRenderThread()) {
243
0
    Loop()->PostTask(
244
0
      NewRunnableMethod<wr::WindowId>("wr::RenderThread::NewFrameReady",
245
0
                                      this,
246
0
                                      &RenderThread::NewFrameReady,
247
0
                                      aWindowId));
248
0
    return;
249
0
  }
250
0
251
0
  if (IsDestroyed(aWindowId)) {
252
0
    return;
253
0
  }
254
0
255
0
  if (mHandlingDeviceReset) {
256
0
    return;
257
0
  }
258
0
259
0
  TimeStamp startTime;
260
0
261
0
  { // scope lock
262
0
    MutexAutoLock lock(mFrameCountMapLock);
263
0
    auto it = mWindowInfos.find(AsUint64(aWindowId));
264
0
    MOZ_ASSERT(it != mWindowInfos.end());
265
0
    WindowInfo* info = it->second;
266
0
    MOZ_ASSERT(info->mPendingCount > 0);
267
0
    startTime = info->mStartTimes.front();
268
0
  }
269
0
270
0
  UpdateAndRender(aWindowId, startTime);
271
0
  FrameRenderingComplete(aWindowId);
272
0
}
273
274
void
275
RenderThread::WakeUp(wr::WindowId aWindowId)
276
0
{
277
0
  if (mHasShutdown) {
278
0
    return;
279
0
  }
280
0
281
0
  if (!IsInRenderThread()) {
282
0
    Loop()->PostTask(
283
0
      NewRunnableMethod<wr::WindowId>("wr::RenderThread::WakeUp",
284
0
                                      this,
285
0
                                      &RenderThread::WakeUp,
286
0
                                      aWindowId));
287
0
    return;
288
0
  }
289
0
290
0
  if (IsDestroyed(aWindowId)) {
291
0
    return;
292
0
  }
293
0
294
0
  if (mHandlingDeviceReset) {
295
0
    return;
296
0
  }
297
0
298
0
  auto it = mRenderers.find(aWindowId);
299
0
  MOZ_ASSERT(it != mRenderers.end());
300
0
  if (it != mRenderers.end()) {
301
0
    it->second->Update();
302
0
  }
303
0
}
304
305
void
306
RenderThread::RunEvent(wr::WindowId aWindowId, UniquePtr<RendererEvent> aEvent)
307
0
{
308
0
  if (!IsInRenderThread()) {
309
0
    Loop()->PostTask(
310
0
      NewRunnableMethod<wr::WindowId, UniquePtr<RendererEvent>&&>(
311
0
        "wr::RenderThread::RunEvent",
312
0
        this,
313
0
        &RenderThread::RunEvent,
314
0
        aWindowId,
315
0
        std::move(aEvent)));
316
0
    return;
317
0
  }
318
0
319
0
  aEvent->Run(*this, aWindowId);
320
0
  aEvent = nullptr;
321
0
}
322
323
static void
324
NotifyDidRender(layers::CompositorBridgeParent* aBridge,
325
                wr::WrPipelineInfo aInfo,
326
                TimeStamp aStart,
327
                TimeStamp aEnd)
328
0
{
329
0
  if (aBridge->GetWrBridge()) {
330
0
    aBridge->GetWrBridge()->RecordFrame();
331
0
  }
332
0
333
0
  for (uintptr_t i = 0; i < aInfo.epochs.length; i++) {
334
0
    aBridge->NotifyPipelineRendered(
335
0
        aInfo.epochs.data[i].pipeline_id,
336
0
        aInfo.epochs.data[i].epoch,
337
0
        aStart,
338
0
        aEnd);
339
0
  }
340
0
341
0
  wr_pipeline_info_delete(aInfo);
342
0
}
343
344
void
345
RenderThread::UpdateAndRender(wr::WindowId aWindowId,
346
                              const TimeStamp& aStartTime,
347
                              bool aReadback)
348
0
{
349
0
  AUTO_PROFILER_TRACING("Paint", "Composite");
350
0
  MOZ_ASSERT(IsInRenderThread());
351
0
352
0
  auto it = mRenderers.find(aWindowId);
353
0
  MOZ_ASSERT(it != mRenderers.end());
354
0
  if (it == mRenderers.end()) {
355
0
    return;
356
0
  }
357
0
358
0
  auto& renderer = it->second;
359
0
360
0
  bool ret = renderer->UpdateAndRender(aReadback);
361
0
  if (!ret) {
362
0
    // Render did not happen, do not call NotifyDidRender.
363
0
    return;
364
0
  }
365
0
366
0
  TimeStamp end = TimeStamp::Now();
367
0
368
0
  auto info = renderer->FlushPipelineInfo();
369
0
  RefPtr<layers::AsyncImagePipelineManager> pipelineMgr =
370
0
      renderer->GetCompositorBridge()->GetAsyncImagePipelineManager();
371
0
  // pipelineMgr should always be non-null here because it is only nulled out
372
0
  // after the WebRenderAPI instance for the CompositorBridgeParent is
373
0
  // destroyed, and that destruction blocks until the renderer thread has
374
0
  // removed the relevant renderer. And after that happens we should never reach
375
0
  // this code at all; it would bail out at the mRenderers.find check above.
376
0
  MOZ_ASSERT(pipelineMgr);
377
0
  pipelineMgr->NotifyPipelinesUpdated(info);
378
0
379
0
  layers::CompositorThreadHolder::Loop()->PostTask(NewRunnableFunction(
380
0
    "NotifyDidRenderRunnable",
381
0
    &NotifyDidRender,
382
0
    renderer->GetCompositorBridge(),
383
0
    info,
384
0
    aStartTime, end
385
0
  ));
386
0
}
387
388
void
389
RenderThread::Pause(wr::WindowId aWindowId)
390
0
{
391
0
  MOZ_ASSERT(IsInRenderThread());
392
0
393
0
  auto it = mRenderers.find(aWindowId);
394
0
  MOZ_ASSERT(it != mRenderers.end());
395
0
  if (it == mRenderers.end()) {
396
0
    return;
397
0
  }
398
0
  auto& renderer = it->second;
399
0
  renderer->Pause();
400
0
}
401
402
bool
403
RenderThread::Resume(wr::WindowId aWindowId)
404
0
{
405
0
  MOZ_ASSERT(IsInRenderThread());
406
0
407
0
  auto it = mRenderers.find(aWindowId);
408
0
  MOZ_ASSERT(it != mRenderers.end());
409
0
  if (it == mRenderers.end()) {
410
0
    return false;
411
0
  }
412
0
  auto& renderer = it->second;
413
0
  return renderer->Resume();
414
0
}
415
416
bool
417
RenderThread::TooManyPendingFrames(wr::WindowId aWindowId)
418
0
{
419
0
  const int64_t maxFrameCount = 1;
420
0
421
0
  // Too many pending frames if pending frames exit more than maxFrameCount
422
0
  // or if RenderBackend is still processing a frame.
423
0
424
0
  MutexAutoLock lock(mFrameCountMapLock);
425
0
  auto it = mWindowInfos.find(AsUint64(aWindowId));
426
0
  if (it == mWindowInfos.end()) {
427
0
    MOZ_ASSERT(false);
428
0
    return true;
429
0
  }
430
0
  WindowInfo* info = it->second;
431
0
432
0
  if (info->mPendingCount > maxFrameCount) {
433
0
    return true;
434
0
  }
435
0
  MOZ_ASSERT(info->mPendingCount >= info->mRenderingCount);
436
0
  return info->mPendingCount > info->mRenderingCount;
437
0
}
438
439
bool
440
RenderThread::IsDestroyed(wr::WindowId aWindowId)
441
0
{
442
0
  MutexAutoLock lock(mFrameCountMapLock);
443
0
  auto it = mWindowInfos.find(AsUint64(aWindowId));
444
0
  if (it == mWindowInfos.end()) {
445
0
    return true;
446
0
  }
447
0
448
0
  return it->second->mIsDestroyed;
449
0
}
450
451
void
452
RenderThread::SetDestroyed(wr::WindowId aWindowId)
453
0
{
454
0
  MutexAutoLock lock(mFrameCountMapLock);
455
0
  auto it = mWindowInfos.find(AsUint64(aWindowId));
456
0
  if (it == mWindowInfos.end()) {
457
0
    MOZ_ASSERT(false);
458
0
    return;
459
0
  }
460
0
  it->second->mIsDestroyed = true;
461
0
}
462
463
void
464
RenderThread::IncPendingFrameCount(wr::WindowId aWindowId, const TimeStamp& aStartTime)
465
0
{
466
0
  MutexAutoLock lock(mFrameCountMapLock);
467
0
  auto it = mWindowInfos.find(AsUint64(aWindowId));
468
0
  if (it == mWindowInfos.end()) {
469
0
    MOZ_ASSERT(false);
470
0
    return;
471
0
  }
472
0
  it->second->mPendingCount++;
473
0
  it->second->mStartTimes.push(aStartTime);
474
0
}
475
476
void
477
RenderThread::DecPendingFrameCount(wr::WindowId aWindowId)
478
0
{
479
0
  MutexAutoLock lock(mFrameCountMapLock);
480
0
  auto it = mWindowInfos.find(AsUint64(aWindowId));
481
0
  if (it == mWindowInfos.end()) {
482
0
    MOZ_ASSERT(false);
483
0
    return;
484
0
  }
485
0
  WindowInfo* info = it->second;
486
0
  MOZ_ASSERT(info->mPendingCount > 0);
487
0
  if (info->mPendingCount <= 0) {
488
0
    return;
489
0
  }
490
0
  info->mPendingCount--;
491
0
  // This function gets called for "nop frames" where nothing was rendered or
492
0
  // composited. But we count this time because the non-WR codepath equivalent
493
0
  // in CompositorBridgeParent::ComposeToTarget also counts such frames. And
494
0
  // anyway this should be relatively infrequent so it shouldn't skew the
495
0
  // numbers much.
496
0
  mozilla::Telemetry::AccumulateTimeDelta(mozilla::Telemetry::COMPOSITE_TIME,
497
0
                                          info->mStartTimes.front());
498
0
  info->mStartTimes.pop();
499
0
}
500
501
void
502
RenderThread::IncRenderingFrameCount(wr::WindowId aWindowId)
503
0
{
504
0
  MutexAutoLock lock(mFrameCountMapLock);
505
0
  auto it = mWindowInfos.find(AsUint64(aWindowId));
506
0
  if (it == mWindowInfos.end()) {
507
0
    MOZ_ASSERT(false);
508
0
    return;
509
0
  }
510
0
  it->second->mRenderingCount++;
511
0
}
512
513
void
514
RenderThread::FrameRenderingComplete(wr::WindowId aWindowId)
515
0
{
516
0
  MutexAutoLock lock(mFrameCountMapLock);
517
0
  auto it = mWindowInfos.find(AsUint64(aWindowId));
518
0
  if (it == mWindowInfos.end()) {
519
0
    MOZ_ASSERT(false);
520
0
    return;
521
0
  }
522
0
  WindowInfo* info = it->second;
523
0
  MOZ_ASSERT(info->mPendingCount > 0);
524
0
  MOZ_ASSERT(info->mRenderingCount > 0);
525
0
  if (info->mPendingCount <= 0) {
526
0
    return;
527
0
  }
528
0
  info->mPendingCount--;
529
0
  info->mRenderingCount--;
530
0
  // The start time is from WebRenderBridgeParent::CompositeToTarget. From that
531
0
  // point until now (when the frame is finally pushed to the screen) is
532
0
  // equivalent to the COMPOSITE_TIME metric in the non-WR codepath.
533
0
  mozilla::Telemetry::AccumulateTimeDelta(mozilla::Telemetry::COMPOSITE_TIME,
534
0
                                          info->mStartTimes.front());
535
0
  info->mStartTimes.pop();
536
0
}
537
538
void
539
RenderThread::RegisterExternalImage(uint64_t aExternalImageId, already_AddRefed<RenderTextureHost> aTexture)
540
0
{
541
0
  MutexAutoLock lock(mRenderTextureMapLock);
542
0
543
0
  if (mHasShutdown) {
544
0
    return;
545
0
  }
546
0
  MOZ_ASSERT(mRenderTextures.find(aExternalImageId) == mRenderTextures.end());
547
0
  mRenderTextures.emplace(aExternalImageId, std::move(aTexture));
548
0
}
549
550
void
551
RenderThread::UnregisterExternalImage(uint64_t aExternalImageId)
552
0
{
553
0
  MutexAutoLock lock(mRenderTextureMapLock);
554
0
  if (mHasShutdown) {
555
0
    return;
556
0
  }
557
0
  auto it = mRenderTextures.find(aExternalImageId);
558
0
  MOZ_ASSERT(it != mRenderTextures.end());
559
0
  if (it == mRenderTextures.end()) {
560
0
    return;
561
0
  }
562
0
  if (!IsInRenderThread()) {
563
0
    // The RenderTextureHost should be released in render thread. So, post the
564
0
    // deletion task here.
565
0
    // The shmem and raw buffer are owned by compositor ipc channel. It's
566
0
    // possible that RenderTextureHost is still exist after the shmem/raw buffer
567
0
    // deletion. Then the buffer in RenderTextureHost becomes invalid. It's fine
568
0
    // for this situation. Gecko will only release the buffer if WR doesn't need
569
0
    // it. So, no one will access the invalid buffer in RenderTextureHost.
570
0
    RefPtr<RenderTextureHost> texture = it->second;
571
0
    mRenderTextures.erase(it);
572
0
    mRenderTexturesDeferred.emplace_back(std::move(texture));
573
0
    Loop()->PostTask(NewRunnableMethod(
574
0
      "RenderThread::DeferredRenderTextureHostDestroy",
575
0
      this, &RenderThread::DeferredRenderTextureHostDestroy
576
0
    ));
577
0
  } else {
578
0
    mRenderTextures.erase(it);
579
0
  }
580
0
}
581
582
void
583
RenderThread::UpdateRenderTextureHost(uint64_t aSrcExternalImageId, uint64_t aWrappedExternalImageId)
584
0
{
585
0
  MOZ_ASSERT(aSrcExternalImageId != aWrappedExternalImageId);
586
0
587
0
  MutexAutoLock lock(mRenderTextureMapLock);
588
0
  if (mHasShutdown) {
589
0
    return;
590
0
  }
591
0
  auto src = mRenderTextures.find(aSrcExternalImageId);
592
0
  auto wrapped = mRenderTextures.find(aWrappedExternalImageId);
593
0
  if (src == mRenderTextures.end() || wrapped == mRenderTextures.end()) {
594
0
    return;
595
0
  }
596
0
  MOZ_ASSERT(src->second->AsRenderTextureHostWrapper());
597
0
  MOZ_ASSERT(!wrapped->second->AsRenderTextureHostWrapper());
598
0
  RenderTextureHostWrapper* wrapper = src->second->AsRenderTextureHostWrapper();
599
0
  if (!wrapper) {
600
0
    MOZ_ASSERT_UNREACHABLE("unexpected to happen");
601
0
    return;
602
0
  }
603
0
  if (!wrapper->IsInited()) {
604
0
    wrapper->UpdateRenderTextureHost(wrapped->second);
605
0
    MOZ_ASSERT(wrapper->IsInited());
606
0
  } else {
607
0
    Loop()->PostTask(NewRunnableMethod<RenderTextureHost*>(
608
0
      "RenderTextureHostWrapper::UpdateRenderTextureHost",
609
0
      wrapper, &RenderTextureHostWrapper::UpdateRenderTextureHost, wrapped->second
610
0
    ));
611
0
  }
612
0
}
613
614
void
615
RenderThread::UnregisterExternalImageDuringShutdown(uint64_t aExternalImageId)
616
0
{
617
0
  MOZ_ASSERT(IsInRenderThread());
618
0
  MutexAutoLock lock(mRenderTextureMapLock);
619
0
  MOZ_ASSERT(mHasShutdown);
620
0
  MOZ_ASSERT(mRenderTextures.find(aExternalImageId) != mRenderTextures.end());
621
0
  mRenderTextures.erase(aExternalImageId);
622
0
}
623
624
void
625
RenderThread::DeferredRenderTextureHostDestroy()
626
0
{
627
0
  MutexAutoLock lock(mRenderTextureMapLock);
628
0
  mRenderTexturesDeferred.clear();
629
0
}
630
631
RenderTextureHost*
632
RenderThread::GetRenderTexture(wr::WrExternalImageId aExternalImageId)
633
0
{
634
0
  MOZ_ASSERT(IsInRenderThread());
635
0
636
0
  MutexAutoLock lock(mRenderTextureMapLock);
637
0
  auto it = mRenderTextures.find(aExternalImageId.mHandle);
638
0
  MOZ_ASSERT(it != mRenderTextures.end());
639
0
  if (it == mRenderTextures.end()) {
640
0
    return nullptr;
641
0
  }
642
0
  return it->second;
643
0
}
644
645
void
646
RenderThread::ProgramCacheTask()
647
0
{
648
0
  ProgramCache();
649
0
}
650
651
void
652
RenderThread::HandleDeviceReset(const char* aWhere, bool aNotify)
653
0
{
654
0
  MOZ_ASSERT(IsInRenderThread());
655
0
656
0
  if (mHandlingDeviceReset) {
657
0
    return;
658
0
  }
659
0
660
0
  if (aNotify) {
661
0
    gfxCriticalNote << "GFX: RenderThread detected a device reset in " << aWhere;
662
0
    if (XRE_IsGPUProcess()) {
663
0
      gfx::GPUParent::GetSingleton()->NotifyDeviceReset();
664
0
    }
665
0
  }
666
0
667
0
  {
668
0
    MutexAutoLock lock(mRenderTextureMapLock);
669
0
    mRenderTexturesDeferred.clear();
670
0
    for (const auto& entry : mRenderTextures) {
671
0
      entry.second->ClearCachedResources();
672
0
    }
673
0
  }
674
0
675
0
  mHandlingDeviceReset = true;
676
0
  // All RenderCompositors will be destroyed by GPUChild::RecvNotifyDeviceReset()
677
0
}
678
679
bool
680
RenderThread::IsHandlingDeviceReset()
681
0
{
682
0
  MOZ_ASSERT(IsInRenderThread());
683
0
  return mHandlingDeviceReset;
684
0
}
685
686
void
687
RenderThread::SimulateDeviceReset()
688
0
{
689
0
  if (!IsInRenderThread()) {
690
0
    Loop()->PostTask(NewRunnableMethod(
691
0
      "RenderThread::SimulateDeviceReset",
692
0
      this, &RenderThread::SimulateDeviceReset
693
0
      ));
694
0
  } else {
695
0
    // When this function is called GPUProcessManager::SimulateDeviceReset() already
696
0
    // triggers destroying all CompositorSessions before re-creating them.
697
0
    HandleDeviceReset("SimulateDeviceReset", /* aNotify */ false);
698
0
  }
699
0
}
700
701
WebRenderProgramCache*
702
RenderThread::ProgramCache()
703
0
{
704
0
  MOZ_ASSERT(IsInRenderThread());
705
0
706
0
  if (!mProgramCache) {
707
0
    mProgramCache = MakeUnique<WebRenderProgramCache>(ThreadPool().Raw());
708
0
  }
709
0
  return mProgramCache.get();
710
0
}
711
712
WebRenderThreadPool::WebRenderThreadPool()
713
0
{
714
0
  mThreadPool = wr_thread_pool_new();
715
0
}
716
717
WebRenderThreadPool::~WebRenderThreadPool()
718
0
{
719
0
  wr_thread_pool_delete(mThreadPool);
720
0
}
721
722
WebRenderProgramCache::WebRenderProgramCache(wr::WrThreadPool* aThreadPool)
723
0
{
724
0
  MOZ_ASSERT(aThreadPool);
725
0
726
0
  nsAutoString path;
727
0
  if (gfxVars::UseWebRenderProgramBinaryDisk()) {
728
0
    path.Append(gfx::gfxVars::ProfDirectory());
729
0
  }
730
0
  mProgramCache = wr_program_cache_new(&path, aThreadPool);
731
0
  wr_try_load_shader_from_disk(mProgramCache);
732
0
}
733
734
WebRenderProgramCache::~WebRenderProgramCache()
735
0
{
736
0
  wr_program_cache_delete(mProgramCache);
737
0
}
738
739
} // namespace wr
740
} // namespace mozilla
741
742
extern "C" {
743
744
static void NewFrameReady(mozilla::wr::WrWindowId aWindowId)
745
0
{
746
0
  mozilla::wr::RenderThread::Get()->IncRenderingFrameCount(aWindowId);
747
0
  mozilla::wr::RenderThread::Get()->NewFrameReady(aWindowId);
748
0
}
749
750
void wr_notifier_wake_up(mozilla::wr::WrWindowId aWindowId)
751
0
{
752
0
  mozilla::wr::RenderThread::Get()->WakeUp(aWindowId);
753
0
}
754
755
void wr_notifier_new_frame_ready(mozilla::wr::WrWindowId aWindowId)
756
0
{
757
0
  NewFrameReady(aWindowId);
758
0
}
759
760
void wr_notifier_nop_frame_done(mozilla::wr::WrWindowId aWindowId)
761
0
{
762
0
  mozilla::wr::RenderThread::Get()->DecPendingFrameCount(aWindowId);
763
0
}
764
765
void wr_notifier_external_event(mozilla::wr::WrWindowId aWindowId, size_t aRawEvent)
766
0
{
767
0
  mozilla::UniquePtr<mozilla::wr::RendererEvent> evt(
768
0
    reinterpret_cast<mozilla::wr::RendererEvent*>(aRawEvent));
769
0
  mozilla::wr::RenderThread::Get()->RunEvent(mozilla::wr::WindowId(aWindowId),
770
0
                                             std::move(evt));
771
0
}
772
773
void wr_schedule_render(mozilla::wr::WrWindowId aWindowId)
774
0
{
775
0
  RefPtr<mozilla::layers::CompositorBridgeParent> cbp =
776
0
      mozilla::layers::CompositorBridgeParent::GetCompositorBridgeParentFromWindowId(aWindowId);
777
0
  if (cbp) {
778
0
    cbp->ScheduleRenderOnCompositorThread();
779
0
  }
780
0
}
781
782
} // extern C