gles2_command_buffer_stub.cc 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. // Copyright (c) 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "gpu/ipc/service/gles2_command_buffer_stub.h"
  5. #include <memory>
  6. #include <utility>
  7. #include "base/bind.h"
  8. #include "base/callback_helpers.h"
  9. #include "base/hash/hash.h"
  10. #include "base/json/json_writer.h"
  11. #include "base/memory/memory_pressure_listener.h"
  12. #include "base/memory/unsafe_shared_memory_region.h"
  13. #include "base/metrics/histogram_macros.h"
  14. #include "base/task/single_thread_task_runner.h"
  15. #include "base/time/time.h"
  16. #include "base/trace_event/trace_event.h"
  17. #include "build/build_config.h"
  18. #include "gpu/command_buffer/common/constants.h"
  19. #include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
  20. #include "gpu/command_buffer/common/mailbox.h"
  21. #include "gpu/command_buffer/common/presentation_feedback_utils.h"
  22. #include "gpu/command_buffer/common/swap_buffers_flags.h"
  23. #include "gpu/command_buffer/service/gl_context_virtual.h"
  24. #include "gpu/command_buffer/service/gl_state_restorer_impl.h"
  25. #include "gpu/command_buffer/service/gpu_fence_manager.h"
  26. #include "gpu/command_buffer/service/logger.h"
  27. #include "gpu/command_buffer/service/mailbox_manager.h"
  28. #include "gpu/command_buffer/service/memory_tracking.h"
  29. #include "gpu/command_buffer/service/scheduler.h"
  30. #include "gpu/command_buffer/service/service_utils.h"
  31. #include "gpu/command_buffer/service/sync_point_manager.h"
  32. #include "gpu/command_buffer/service/transfer_buffer_manager.h"
  33. #include "gpu/config/gpu_crash_keys.h"
  34. #include "gpu/ipc/service/gpu_channel.h"
  35. #include "gpu/ipc/service/gpu_channel_manager.h"
  36. #include "gpu/ipc/service/gpu_channel_manager_delegate.h"
  37. #include "gpu/ipc/service/gpu_memory_buffer_factory.h"
  38. #include "gpu/ipc/service/gpu_watchdog_thread.h"
  39. #include "gpu/ipc/service/image_transport_surface.h"
  40. #include "ui/gfx/buffer_format_util.h"
  41. #include "ui/gfx/gpu_fence.h"
  42. #include "ui/gfx/gpu_fence_handle.h"
  43. #include "ui/gl/gl_bindings.h"
  44. #include "ui/gl/gl_context.h"
  45. #include "ui/gl/gl_implementation.h"
  46. #include "ui/gl/gl_surface_egl.h"
  47. #include "ui/gl/gl_switches.h"
  48. #include "ui/gl/gl_utils.h"
  49. #include "ui/gl/gl_workarounds.h"
  50. #include "ui/gl/init/gl_factory.h"
  51. #if BUILDFLAG(IS_WIN)
  52. #include "base/win/win_util.h"
  53. #endif
  54. namespace gpu {
  55. GLES2CommandBufferStub::GLES2CommandBufferStub(
  56. GpuChannel* channel,
  57. const mojom::CreateCommandBufferParams& init_params,
  58. CommandBufferId command_buffer_id,
  59. SequenceId sequence_id,
  60. int32_t stream_id,
  61. int32_t route_id)
  62. : CommandBufferStub(channel,
  63. init_params,
  64. command_buffer_id,
  65. sequence_id,
  66. stream_id,
  67. route_id),
  68. gles2_decoder_(nullptr) {}
  69. GLES2CommandBufferStub::~GLES2CommandBufferStub() = default;
  70. gpu::ContextResult GLES2CommandBufferStub::Initialize(
  71. CommandBufferStub* share_command_buffer_stub,
  72. const mojom::CreateCommandBufferParams& init_params,
  73. base::UnsafeSharedMemoryRegion shared_state_shm) {
  74. TRACE_EVENT0("gpu", "GLES2CommandBufferStub::Initialize");
  75. UpdateActiveUrl();
  76. GpuChannelManager* manager = channel_->gpu_channel_manager();
  77. DCHECK(manager);
  78. memory_tracker_ = CreateMemoryTracker();
  79. if (share_command_buffer_stub) {
  80. context_group_ =
  81. share_command_buffer_stub->decoder_context()->GetContextGroup();
  82. if (!context_group_) {
  83. LOG(ERROR) << "ContextResult::kFatalFailure: attempt to create a GLES2 "
  84. "context sharing with a non-GLES2 context";
  85. return gpu::ContextResult::kFatalFailure;
  86. }
  87. if (context_group_->bind_generates_resource() !=
  88. init_params.attribs.bind_generates_resource) {
  89. LOG(ERROR) << "ContextResult::kFatalFailure: attempt to create a shared "
  90. "GLES2 context with inconsistent bind_generates_resource";
  91. return gpu::ContextResult::kFatalFailure;
  92. }
  93. } else {
  94. scoped_refptr<gles2::FeatureInfo> feature_info = new gles2::FeatureInfo(
  95. manager->gpu_driver_bug_workarounds(), manager->gpu_feature_info());
  96. gpu::GpuMemoryBufferFactory* gmb_factory =
  97. manager->gpu_memory_buffer_factory();
  98. context_group_ = new gles2::ContextGroup(
  99. manager->gpu_preferences(), gles2::PassthroughCommandDecoderSupported(),
  100. manager->mailbox_manager(), CreateMemoryTracker(),
  101. manager->shader_translator_cache(),
  102. manager->framebuffer_completeness_cache(), feature_info,
  103. init_params.attribs.bind_generates_resource,
  104. gmb_factory ? gmb_factory->AsImageFactory() : nullptr,
  105. manager->watchdog() /* progress_reporter */,
  106. manager->gpu_feature_info(), manager->discardable_manager(),
  107. manager->passthrough_discardable_manager(),
  108. manager->shared_image_manager());
  109. }
  110. #if BUILDFLAG(IS_MAC)
  111. // Virtualize GpuPreference::kLowPower contexts by default on OS X to prevent
  112. // performance regressions when enabling FCM.
  113. // http://crbug.com/180463
  114. if (init_params.attribs.gpu_preference == gl::GpuPreference::kLowPower)
  115. use_virtualized_gl_context_ = true;
  116. #endif
  117. use_virtualized_gl_context_ |=
  118. context_group_->feature_info()->workarounds().use_virtualized_gl_contexts;
  119. bool offscreen = (surface_handle_ == kNullSurfaceHandle);
  120. gl::GLSurface* default_surface = manager->default_offscreen_surface();
  121. // On low-spec Android devices, the default offscreen surface is
  122. // RGB565, but WebGL rendering contexts still ask for RGBA8888 mode.
  123. // That combination works for offscreen rendering, we can still use
  124. // a virtualized context with the RGB565 backing surface since we're
  125. // not drawing to that. Explicitly set that as the desired surface
  126. // format to ensure it's treated as compatible where applicable.
  127. gl::GLSurfaceFormat surface_format =
  128. offscreen ? default_surface->GetFormat() : gl::GLSurfaceFormat();
  129. #if BUILDFLAG(IS_ANDROID)
  130. if (init_params.attribs.red_size <= 5 &&
  131. init_params.attribs.green_size <= 6 &&
  132. init_params.attribs.blue_size <= 5 &&
  133. init_params.attribs.alpha_size == 0) {
  134. // We hit this code path when creating the onscreen render context
  135. // used for compositing on low-end Android devices.
  136. //
  137. // TODO(klausw): explicitly copy rgba sizes? Currently the formats
  138. // supported are only RGB565 and default (RGBA8888).
  139. surface_format.SetRGB565();
  140. DVLOG(1) << __FUNCTION__ << ": Choosing RGB565 mode.";
  141. }
  142. // We can only use virtualized contexts for onscreen command buffers if their
  143. // config is compatible with the offscreen ones - otherwise MakeCurrent fails.
  144. // Example use case is a client requesting an onscreen RGBA8888 buffer for
  145. // fullscreen video on a low-spec device with RGB565 default format.
  146. if (!surface_format.IsCompatible(default_surface->GetFormat()) && !offscreen)
  147. use_virtualized_gl_context_ = false;
  148. #endif
  149. command_buffer_ = std::make_unique<CommandBufferService>(
  150. this, context_group_->memory_tracker());
  151. gles2_decoder_ = gles2::GLES2Decoder::Create(
  152. this, command_buffer_.get(), manager->outputter(), context_group_.get());
  153. set_decoder_context(std::unique_ptr<DecoderContext>(gles2_decoder_));
  154. sync_point_client_state_ =
  155. channel_->sync_point_manager()->CreateSyncPointClientState(
  156. CommandBufferNamespace::GPU_IO, command_buffer_id_, sequence_id_);
  157. gl::GpuPreference gpu_preference = init_params.attribs.gpu_preference;
  158. // If the user queries a low-power context, it's better to use whatever the
  159. // default GPU used by Chrome is, which may be different than the low-power
  160. // GPU determined by GLDisplayManager.
  161. if (gpu_preference == gl::GpuPreference::kLowPower ||
  162. gpu_preference == gl::GpuPreference::kNone) {
  163. gpu_preference = gl::GpuPreference::kDefault;
  164. }
  165. gl::GLDisplay* display = gl::GetDisplay(gpu_preference);
  166. DCHECK(display);
  167. if (!display->IsInitialized()) {
  168. gl::GLDisplay* initialized_display =
  169. gl::init::InitializeGLOneOffPlatformImplementation(
  170. /*fallback_to_software_gl=*/false, /*disable_gl_drawing=*/false,
  171. /*init_extensions=*/true,
  172. /*system_device_id=*/display->system_device_id());
  173. DCHECK_EQ(initialized_display, display);
  174. }
  175. if (offscreen) {
  176. // Do we want to create an offscreen rendering context suitable
  177. // for directly drawing to a separately supplied surface? In that
  178. // case, we must ensure that the surface used for context creation
  179. // is compatible with the requested attributes. This is explicitly
  180. // opt-in since some context such as for NaCl request custom
  181. // attributes but don't expect to get their own surface, and not
  182. // all surface factories support custom formats.
  183. if (init_params.attribs.own_offscreen_surface) {
  184. if (init_params.attribs.depth_size > 0) {
  185. surface_format.SetDepthBits(init_params.attribs.depth_size);
  186. }
  187. if (init_params.attribs.samples > 0) {
  188. surface_format.SetSamples(init_params.attribs.samples);
  189. }
  190. if (init_params.attribs.stencil_size > 0) {
  191. surface_format.SetStencilBits(init_params.attribs.stencil_size);
  192. }
  193. // Currently, we can't separately control alpha channel for surfaces,
  194. // it's generally enabled by default except for RGB565 and (on desktop)
  195. // smaller-than-32bit formats.
  196. //
  197. // TODO(klausw): use init_params.attribs.alpha_size here if possible.
  198. }
  199. if (!surface_format.IsCompatible(default_surface->GetFormat())) {
  200. DVLOG(1) << __FUNCTION__ << ": Hit the OwnOffscreenSurface path";
  201. use_virtualized_gl_context_ = false;
  202. surface_ = gl::init::CreateOffscreenGLSurfaceWithFormat(
  203. display, gfx::Size(), surface_format);
  204. if (!surface_) {
  205. LOG(ERROR)
  206. << "ContextResult::kSurfaceFailure: Failed to create surface.";
  207. return gpu::ContextResult::kSurfaceFailure;
  208. }
  209. } else {
  210. surface_ = default_surface;
  211. }
  212. } else {
  213. switch (init_params.attribs.color_space) {
  214. case COLOR_SPACE_UNSPECIFIED:
  215. surface_format.SetColorSpace(
  216. gl::GLSurfaceFormat::COLOR_SPACE_UNSPECIFIED);
  217. break;
  218. case COLOR_SPACE_SRGB:
  219. surface_format.SetColorSpace(gl::GLSurfaceFormat::COLOR_SPACE_SRGB);
  220. break;
  221. case COLOR_SPACE_DISPLAY_P3:
  222. surface_format.SetColorSpace(
  223. gl::GLSurfaceFormat::COLOR_SPACE_DISPLAY_P3);
  224. break;
  225. }
  226. surface_ = ImageTransportSurface::CreateNativeSurface(
  227. display, weak_ptr_factory_.GetWeakPtr(), surface_handle_,
  228. surface_format);
  229. if (!surface_ || !surface_->Initialize(surface_format)) {
  230. surface_ = nullptr;
  231. LOG(ERROR) << "ContextResult::kSurfaceFailure: Failed to create surface.";
  232. return gpu::ContextResult::kSurfaceFailure;
  233. }
  234. if (init_params.attribs.enable_swap_timestamps_if_supported &&
  235. surface_->SupportsSwapTimestamps())
  236. surface_->SetEnableSwapTimestamps();
  237. }
  238. if (context_group_->use_passthrough_cmd_decoder()) {
  239. // Virtualized contexts don't work with passthrough command decoder.
  240. // See https://crbug.com/914976
  241. use_virtualized_gl_context_ = false;
  242. // When using the passthrough command decoder, only share with other
  243. // contexts in the explicitly requested share group
  244. if (share_command_buffer_stub) {
  245. share_group_ = share_command_buffer_stub->share_group();
  246. } else {
  247. share_group_ = base::MakeRefCounted<gl::GLShareGroup>();
  248. }
  249. } else {
  250. // When using the validating command decoder, always use the global share
  251. // group
  252. share_group_ = channel_->share_group();
  253. }
  254. // TODO(sunnyps): Should this use ScopedCrashKey instead?
  255. crash_keys::gpu_gl_context_is_virtual.Set(use_virtualized_gl_context_ ? "1"
  256. : "0");
  257. scoped_refptr<gl::GLContext> context;
  258. if (use_virtualized_gl_context_ && share_group_) {
  259. context = share_group_->shared_context();
  260. if (context && (!context->MakeCurrent(surface_.get()) ||
  261. context->CheckStickyGraphicsResetStatus() != GL_NO_ERROR)) {
  262. context = nullptr;
  263. }
  264. if (!context) {
  265. context = gl::init::CreateGLContext(
  266. share_group_.get(), surface_.get(),
  267. GenerateGLContextAttribs(init_params.attribs, context_group_.get()));
  268. if (!context) {
  269. // TODO(piman): This might not be fatal, we could recurse into
  270. // CreateGLContext to get more info, tho it should be exceedingly
  271. // rare and may not be recoverable anyway.
  272. LOG(ERROR) << "ContextResult::kFatalFailure: "
  273. "Failed to create shared context for virtualization.";
  274. return gpu::ContextResult::kFatalFailure;
  275. }
  276. // Ensure that context creation did not lose track of the intended share
  277. // group.
  278. DCHECK(context->share_group() == share_group_.get());
  279. share_group_->SetSharedContext(context.get());
  280. // This needs to be called against the real shared context, not the
  281. // virtual context created below.
  282. manager->gpu_feature_info().ApplyToGLContext(context.get());
  283. }
  284. // This should be either:
  285. // (1) a non-virtual GL context, or
  286. // (2) a mock/stub context.
  287. DCHECK(context->GetHandle() ||
  288. gl::GetGLImplementation() == gl::kGLImplementationMockGL ||
  289. gl::GetGLImplementation() == gl::kGLImplementationStubGL);
  290. context = base::MakeRefCounted<GLContextVirtual>(
  291. share_group_.get(), context.get(), gles2_decoder_->AsWeakPtr());
  292. if (!context->Initialize(surface_.get(),
  293. GenerateGLContextAttribs(init_params.attribs,
  294. context_group_.get()))) {
  295. // The real context created above for the default offscreen surface
  296. // might not be compatible with this surface.
  297. context = nullptr;
  298. // TODO(piman): This might not be fatal, we could recurse into
  299. // CreateGLContext to get more info, tho it should be exceedingly
  300. // rare and may not be recoverable anyway.
  301. LOG(ERROR) << "ContextResult::kFatalFailure: "
  302. "Failed to initialize virtual GL context.";
  303. return gpu::ContextResult::kFatalFailure;
  304. }
  305. } else {
  306. context = gl::init::CreateGLContext(
  307. share_group_.get(), surface_.get(),
  308. GenerateGLContextAttribs(init_params.attribs, context_group_.get()));
  309. if (!context) {
  310. // TODO(piman): This might not be fatal, we could recurse into
  311. // CreateGLContext to get more info, tho it should be exceedingly
  312. // rare and may not be recoverable anyway.
  313. LOG(ERROR) << "ContextResult::kFatalFailure: Failed to create context.";
  314. return gpu::ContextResult::kFatalFailure;
  315. }
  316. manager->gpu_feature_info().ApplyToGLContext(context.get());
  317. }
  318. if (!context->MakeCurrent(surface_.get())) {
  319. LOG(ERROR) << "ContextResult::kTransientFailure: "
  320. "Failed to make context current.";
  321. return gpu::ContextResult::kTransientFailure;
  322. }
  323. // The GLStateRestorer is not used with the passthrough command decoder
  324. // because not all state is tracked in the decoder. Virtualized contexts are
  325. // also not used.
  326. if (!context->GetGLStateRestorer() &&
  327. !context_group_->use_passthrough_cmd_decoder()) {
  328. context->SetGLStateRestorer(
  329. new GLStateRestorerImpl(gles2_decoder_->AsWeakPtr()));
  330. }
  331. if (!context_group_->has_program_cache() &&
  332. !context_group_->feature_info()->workarounds().disable_program_cache) {
  333. context_group_->set_program_cache(manager->program_cache());
  334. }
  335. // Initialize the decoder with either the view or pbuffer GLContext.
  336. auto result = gles2_decoder_->Initialize(surface_, context, offscreen,
  337. gpu::gles2::DisallowedFeatures(),
  338. init_params.attribs);
  339. if (result != gpu::ContextResult::kSuccess) {
  340. DLOG(ERROR) << "Failed to initialize decoder.";
  341. return result;
  342. }
  343. if (manager->gpu_preferences().enable_gpu_service_logging) {
  344. gles2_decoder_->SetLogCommands(true);
  345. }
  346. const size_t kSharedStateSize = sizeof(CommandBufferSharedState);
  347. base::WritableSharedMemoryMapping shared_state_mapping =
  348. shared_state_shm.MapAt(0, kSharedStateSize);
  349. if (!shared_state_mapping.IsValid()) {
  350. LOG(ERROR) << "ContextResult::kFatalFailure: "
  351. "Failed to map shared state buffer.";
  352. return gpu::ContextResult::kFatalFailure;
  353. }
  354. command_buffer_->SetSharedStateBuffer(MakeBackingFromSharedMemory(
  355. std::move(shared_state_shm), std::move(shared_state_mapping)));
  356. if (offscreen && !active_url_.is_empty())
  357. manager->delegate()->DidCreateOffscreenContext(active_url_.url());
  358. if (use_virtualized_gl_context_) {
  359. // If virtualized GL contexts are in use, then real GL context state
  360. // is in an indeterminate state, since the GLStateRestorer was not
  361. // initialized at the time the GLContextVirtual was made current. In
  362. // the case that this command decoder is the next one to be
  363. // processed, force a "full virtual" MakeCurrent to be performed.
  364. // Note that GpuChannel's initialization of the gpu::Capabilities
  365. // expects the context to be left current.
  366. context->ForceReleaseVirtuallyCurrent();
  367. if (!context->MakeCurrent(surface_.get())) {
  368. LOG(ERROR) << "ContextResult::kTransientFailure: "
  369. "Failed to make context current after initialization.";
  370. return gpu::ContextResult::kTransientFailure;
  371. }
  372. }
  373. manager->delegate()->DidCreateContextSuccessfully();
  374. initialized_ = true;
  375. return gpu::ContextResult::kSuccess;
  376. }
  377. #if BUILDFLAG(IS_WIN)
  378. void GLES2CommandBufferStub::DidCreateAcceleratedSurfaceChildWindow(
  379. SurfaceHandle parent_window,
  380. SurfaceHandle child_window) {
  381. GpuChannelManager* gpu_channel_manager = channel_->gpu_channel_manager();
  382. gpu_channel_manager->delegate()->SendCreatedChildWindow(parent_window,
  383. child_window);
  384. }
  385. #endif
  386. const gles2::FeatureInfo* GLES2CommandBufferStub::GetFeatureInfo() const {
  387. return context_group_->feature_info();
  388. }
  389. const GpuPreferences& GLES2CommandBufferStub::GetGpuPreferences() const {
  390. return context_group_->gpu_preferences();
  391. }
  392. viz::GpuVSyncCallback GLES2CommandBufferStub::GetGpuVSyncCallback() {
  393. return viz::GpuVSyncCallback();
  394. }
  395. base::TimeDelta GLES2CommandBufferStub::GetGpuBlockedTimeSinceLastSwap() {
  396. return channel_->scheduler()->TakeTotalBlockingTime();
  397. }
  398. MemoryTracker* GLES2CommandBufferStub::GetContextGroupMemoryTracker() const {
  399. return context_group_->memory_tracker();
  400. }
  401. void GLES2CommandBufferStub::OnGpuSwitched(
  402. gl::GpuPreference active_gpu_heuristic) {
  403. client().OnGpuSwitched(active_gpu_heuristic);
  404. }
  405. void GLES2CommandBufferStub::OnTakeFrontBuffer(const Mailbox& mailbox) {
  406. TRACE_EVENT0("gpu", "CommandBufferStub::OnTakeFrontBuffer");
  407. DCHECK(gles2_decoder_);
  408. gles2_decoder_->TakeFrontBuffer(mailbox);
  409. }
  410. void GLES2CommandBufferStub::OnReturnFrontBuffer(const Mailbox& mailbox,
  411. bool is_lost) {
  412. // No need to pull texture updates.
  413. gles2_decoder_->ReturnFrontBuffer(mailbox, is_lost);
  414. }
  415. void GLES2CommandBufferStub::CreateGpuFenceFromHandle(
  416. uint32_t gpu_fence_id,
  417. gfx::GpuFenceHandle handle) {
  418. ScopedContextOperation operation(*this);
  419. if (!operation.is_context_current())
  420. return;
  421. if (!context_group_->feature_info()->feature_flags().chromium_gpu_fence) {
  422. DLOG(ERROR) << "CHROMIUM_gpu_fence unavailable";
  423. command_buffer_->SetParseError(error::kLostContext);
  424. return;
  425. }
  426. if (gles2_decoder_->GetGpuFenceManager()->CreateGpuFenceFromHandle(
  427. gpu_fence_id, std::move(handle)))
  428. return;
  429. // The insertion failed. This shouldn't happen, force context loss to avoid
  430. // inconsistent state.
  431. command_buffer_->SetParseError(error::kLostContext);
  432. CheckContextLost();
  433. }
  434. void GLES2CommandBufferStub::GetGpuFenceHandle(
  435. uint32_t gpu_fence_id,
  436. GetGpuFenceHandleCallback callback) {
  437. ScopedContextOperation operation(*this);
  438. if (!operation.is_context_current())
  439. return;
  440. if (!context_group_->feature_info()->feature_flags().chromium_gpu_fence) {
  441. DLOG(ERROR) << "CHROMIUM_gpu_fence unavailable";
  442. command_buffer_->SetParseError(error::kLostContext);
  443. return;
  444. }
  445. auto* manager = gles2_decoder_->GetGpuFenceManager();
  446. gfx::GpuFenceHandle handle;
  447. if (manager->IsValidGpuFence(gpu_fence_id)) {
  448. std::unique_ptr<gfx::GpuFence> gpu_fence =
  449. manager->GetGpuFence(gpu_fence_id);
  450. handle = gpu_fence->GetGpuFenceHandle().Clone();
  451. } else {
  452. // Retrieval failed. This shouldn't happen, force context loss to avoid
  453. // inconsistent state.
  454. DLOG(ERROR) << "GpuFence not found";
  455. command_buffer_->SetParseError(error::kLostContext);
  456. CheckContextLost();
  457. }
  458. std::move(callback).Run(std::move(handle));
  459. }
  460. void GLES2CommandBufferStub::OnSwapBuffers(uint64_t swap_id, uint32_t flags) {}
  461. } // namespace gpu