image_transport_surface_overlay_mac.mm 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680
  1. // Copyright 2015 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/image_transport_surface_overlay_mac.h"
  5. #include <memory>
  6. #include <sstream>
  7. #include "base/bind.h"
  8. #include "base/callback_helpers.h"
  9. #include "base/command_line.h"
  10. #include "base/metrics/histogram_macros.h"
  11. #include "base/threading/thread_task_runner_handle.h"
  12. #include "base/time/time.h"
  13. #include "base/trace_event/trace_event.h"
  14. #include "gpu/command_buffer/common/swap_buffers_complete_params.h"
  15. #include "gpu/ipc/service/gpu_channel_manager.h"
  16. #include "gpu/ipc/service/gpu_channel_manager_delegate.h"
  17. #include "gpu/ipc/service/image_transport_surface_delegate.h"
  18. #include "ui/accelerated_widget_mac/ca_layer_tree_coordinator.h"
  19. #include "ui/accelerated_widget_mac/io_surface_context.h"
  20. #include "ui/base/cocoa/remote_layer_api.h"
  21. #include "ui/base/ui_base_switches.h"
  22. #include "ui/gfx/geometry/rect_conversions.h"
  23. #include "ui/gfx/video_types.h"
  24. #include "ui/gl/ca_renderer_layer_params.h"
  25. #include "ui/gl/gl_context.h"
  26. #include "ui/gl/gl_image_io_surface.h"
  27. #include "ui/gl/gpu_switching_manager.h"
  28. #include "ui/gl/scoped_cgl.h"
  29. namespace gpu {
  30. namespace {
  31. // Control use of AVFoundation to draw video content.
  32. base::Feature kAVFoundationOverlays{"avfoundation-overlays",
  33. base::FEATURE_ENABLED_BY_DEFAULT};
  34. } // namespace
  35. ImageTransportSurfaceOverlayMac::ImageTransportSurfaceOverlayMac(
  36. base::WeakPtr<ImageTransportSurfaceDelegate> delegate)
  37. : delegate_(delegate),
  38. use_remote_layer_api_(ui::RemoteLayerAPISupported()),
  39. scale_factor_(1),
  40. gl_renderer_id_(0),
  41. weak_ptr_factory_(this) {
  42. ui::GpuSwitchingManager::GetInstance()->AddObserver(this);
  43. static bool av_disabled_at_command_line =
  44. !base::FeatureList::IsEnabled(kAVFoundationOverlays);
  45. bool allow_av_sample_buffer_display_layer =
  46. !av_disabled_at_command_line &&
  47. !delegate_->GetFeatureInfo()
  48. ->workarounds()
  49. .disable_av_sample_buffer_display_layer;
  50. ca_layer_tree_coordinator_ = std::make_unique<ui::CALayerTreeCoordinator>(
  51. use_remote_layer_api_, allow_av_sample_buffer_display_layer);
  52. // Create the CAContext to send this to the GPU process, and the layer for
  53. // the context.
  54. if (use_remote_layer_api_) {
  55. CGSConnectionID connection_id = CGSMainConnectionID();
  56. ca_context_.reset([[CAContext contextWithCGSConnection:connection_id
  57. options:@{}] retain]);
  58. [ca_context_ setLayer:ca_layer_tree_coordinator_->GetCALayerForDisplay()];
  59. }
  60. }
  61. ImageTransportSurfaceOverlayMac::~ImageTransportSurfaceOverlayMac() {
  62. ui::GpuSwitchingManager::GetInstance()->RemoveObserver(this);
  63. Destroy();
  64. }
  65. bool ImageTransportSurfaceOverlayMac::Initialize(gl::GLSurfaceFormat format) {
  66. return true;
  67. }
  68. void ImageTransportSurfaceOverlayMac::PrepareToDestroy(bool have_context) {}
  69. void ImageTransportSurfaceOverlayMac::Destroy() {
  70. ca_layer_tree_coordinator_.reset();
  71. }
  72. bool ImageTransportSurfaceOverlayMac::IsOffscreen() {
  73. return false;
  74. }
  75. void ImageTransportSurfaceOverlayMac::ApplyBackpressure() {
  76. TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::ApplyBackpressure");
  77. // Create the fence for the current frame before waiting on the previous
  78. // frame's fence (to maximize CPU and GPU execution overlap).
  79. gl::GLContext* current_context = gl::GLContext::GetCurrent();
  80. uint64_t this_frame_fence = current_context->BackpressureFenceCreate();
  81. current_context->BackpressureFenceWait(previous_frame_fence_);
  82. previous_frame_fence_ = this_frame_fence;
  83. }
  84. void ImageTransportSurfaceOverlayMac::BufferPresented(
  85. gl::GLSurface::PresentationCallback callback,
  86. const gfx::PresentationFeedback& feedback) {
  87. DCHECK(!callback.is_null());
  88. std::move(callback).Run(feedback);
  89. }
  90. gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffersInternal(
  91. gl::GLSurface::SwapCompletionCallback completion_callback,
  92. gl::GLSurface::PresentationCallback presentation_callback) {
  93. TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::SwapBuffersInternal");
  94. constexpr base::TimeDelta kHistogramMinTime = base::Microseconds(5);
  95. constexpr base::TimeDelta kHistogramMaxTime = base::Milliseconds(16);
  96. constexpr int kHistogramTimeBuckets = 50;
  97. // Do a GL fence for flush to apply back-pressure before drawing.
  98. {
  99. base::TimeTicks start_time = base::TimeTicks::Now();
  100. ApplyBackpressure();
  101. UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(
  102. "Gpu.Mac.BackpressureUs", base::TimeTicks::Now() - start_time,
  103. kHistogramMinTime, kHistogramMaxTime, kHistogramTimeBuckets);
  104. }
  105. // Update the CALayer tree in the GPU process.
  106. base::TimeTicks before_transaction_time = base::TimeTicks::Now();
  107. {
  108. TRACE_EVENT0("gpu", "CommitPendingTreesToCA");
  109. ca_layer_tree_coordinator_->CommitPendingTreesToCA();
  110. base::TimeDelta transaction_time =
  111. base::TimeTicks::Now() - before_transaction_time;
  112. UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(
  113. "GPU.IOSurface.CATransactionTimeUs", transaction_time,
  114. kHistogramMinTime, kHistogramMaxTime, kHistogramTimeBuckets);
  115. }
  116. // Populate the CA layer parameters to send to the browser.
  117. gfx::CALayerParams params;
  118. {
  119. TRACE_EVENT_INSTANT2("test_gpu", "SwapBuffers", TRACE_EVENT_SCOPE_THREAD,
  120. "GLImpl", static_cast<int>(gl::GetGLImplementation()),
  121. "width", pixel_size_.width());
  122. if (use_remote_layer_api_) {
  123. params.ca_context_id = [ca_context_ contextId];
  124. } else {
  125. IOSurfaceRef io_surface =
  126. ca_layer_tree_coordinator_->GetIOSurfaceForDisplay();
  127. if (io_surface) {
  128. params.io_surface_mach_port.reset(IOSurfaceCreateMachPort(io_surface));
  129. }
  130. }
  131. params.pixel_size = pixel_size_;
  132. params.scale_factor = scale_factor_;
  133. params.is_empty = false;
  134. }
  135. // Send the swap parameters to the browser.
  136. if (completion_callback) {
  137. base::ThreadTaskRunnerHandle::Get()->PostTask(
  138. FROM_HERE,
  139. base::BindOnce(std::move(completion_callback),
  140. gfx::SwapCompletionResult(
  141. gfx::SwapResult::SWAP_ACK,
  142. std::make_unique<gfx::CALayerParams>(params))));
  143. }
  144. gfx::PresentationFeedback feedback(base::TimeTicks::Now(), base::Hertz(60),
  145. /*flags=*/0);
  146. feedback.ca_layer_error_code = ca_layer_error_code_;
  147. base::ThreadTaskRunnerHandle::Get()->PostTask(
  148. FROM_HERE,
  149. base::BindOnce(&ImageTransportSurfaceOverlayMac::BufferPresented,
  150. weak_ptr_factory_.GetWeakPtr(),
  151. std::move(presentation_callback), feedback));
  152. return gfx::SwapResult::SWAP_ACK;
  153. }
  154. gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffers(
  155. gl::GLSurface::PresentationCallback callback) {
  156. return SwapBuffersInternal(base::DoNothing(), std::move(callback));
  157. }
  158. void ImageTransportSurfaceOverlayMac::SwapBuffersAsync(
  159. gl::GLSurface::SwapCompletionCallback completion_callback,
  160. gl::GLSurface::PresentationCallback presentation_callback) {
  161. SwapBuffersInternal(std::move(completion_callback),
  162. std::move(presentation_callback));
  163. }
  164. gfx::SwapResult ImageTransportSurfaceOverlayMac::PostSubBuffer(
  165. int x,
  166. int y,
  167. int width,
  168. int height,
  169. gl::GLSurface::PresentationCallback callback) {
  170. return SwapBuffersInternal(base::DoNothing(), std::move(callback));
  171. }
  172. void ImageTransportSurfaceOverlayMac::PostSubBufferAsync(
  173. int x,
  174. int y,
  175. int width,
  176. int height,
  177. gl::GLSurface::SwapCompletionCallback completion_callback,
  178. gl::GLSurface::PresentationCallback presentation_callback) {
  179. SwapBuffersInternal(std::move(completion_callback),
  180. std::move(presentation_callback));
  181. }
  182. gfx::SwapResult ImageTransportSurfaceOverlayMac::CommitOverlayPlanes(
  183. gl::GLSurface::PresentationCallback callback) {
  184. return SwapBuffersInternal(base::DoNothing(), std::move(callback));
  185. }
  186. void ImageTransportSurfaceOverlayMac::CommitOverlayPlanesAsync(
  187. gl::GLSurface::SwapCompletionCallback completion_callback,
  188. gl::GLSurface::PresentationCallback presentation_callback) {
  189. SwapBuffersInternal(std::move(completion_callback),
  190. std::move(presentation_callback));
  191. }
  192. bool ImageTransportSurfaceOverlayMac::SupportsPostSubBuffer() {
  193. return true;
  194. }
  195. bool ImageTransportSurfaceOverlayMac::SupportsCommitOverlayPlanes() {
  196. return true;
  197. }
  198. bool ImageTransportSurfaceOverlayMac::SupportsAsyncSwap() {
  199. return true;
  200. }
  201. gfx::Size ImageTransportSurfaceOverlayMac::GetSize() {
  202. return gfx::Size();
  203. }
  204. void* ImageTransportSurfaceOverlayMac::GetHandle() {
  205. return nullptr;
  206. }
  207. gl::GLSurfaceFormat ImageTransportSurfaceOverlayMac::GetFormat() {
  208. return gl::GLSurfaceFormat();
  209. }
  210. bool ImageTransportSurfaceOverlayMac::OnMakeCurrent(gl::GLContext* context) {
  211. // Ensure that the context is on the appropriate GL renderer. The GL renderer
  212. // will generally only change when the GPU changes.
  213. if (gl_renderer_id_ && context)
  214. context->share_group()->SetRendererID(gl_renderer_id_);
  215. return true;
  216. }
  217. bool ImageTransportSurfaceOverlayMac::ScheduleOverlayPlane(
  218. gl::GLImage* image,
  219. std::unique_ptr<gfx::GpuFence> gpu_fence,
  220. const gfx::OverlayPlaneData& overlay_plane_data) {
  221. if (overlay_plane_data.plane_transform != gfx::OVERLAY_TRANSFORM_NONE) {
  222. DLOG(ERROR) << "Invalid overlay plane transform.";
  223. return false;
  224. }
  225. if (overlay_plane_data.z_order) {
  226. DLOG(ERROR) << "Invalid non-zero Z order.";
  227. return false;
  228. }
  229. gl::GLImageIOSurface* io_surface_image =
  230. gl::GLImageIOSurface::FromGLImage(image);
  231. if (!io_surface_image) {
  232. DLOG(ERROR) << "Not an IOSurface image.";
  233. return false;
  234. }
  235. // TODO(1290313): the display_bounds might not need to be rounded to the
  236. // nearest rect as this eventually gets made into a CALayer. CALayers work in
  237. // floats.
  238. const ui::CARendererLayerParams overlay_as_calayer_params(
  239. false, // is_clipped
  240. gfx::Rect(), // clip_rect
  241. gfx::RRectF(), // rounded_corner_bounds
  242. 0, // sorting_context_id
  243. gfx::Transform(), image,
  244. overlay_plane_data.crop_rect, // contents_rect
  245. gfx::ToNearestRect(overlay_plane_data.display_bounds), // rect
  246. SK_ColorTRANSPARENT, // background_color
  247. 0, // edge_aa_mask
  248. 1.f, // opacity
  249. GL_LINEAR, // filter
  250. absl::nullopt, // hdr_metadata
  251. gfx::ProtectedVideoType::kClear); // protected_video_type
  252. return ca_layer_tree_coordinator_->GetPendingCARendererLayerTree()
  253. ->ScheduleCALayer(overlay_as_calayer_params);
  254. }
  255. bool ImageTransportSurfaceOverlayMac::ScheduleCALayer(
  256. const ui::CARendererLayerParams& params) {
  257. if (params.image) {
  258. gl::GLImageIOSurface* io_surface_image =
  259. gl::GLImageIOSurface::FromGLImage(params.image);
  260. if (!io_surface_image) {
  261. DLOG(ERROR) << "Cannot schedule CALayer with non-IOSurface GLImage";
  262. return false;
  263. }
  264. }
  265. return ca_layer_tree_coordinator_->GetPendingCARendererLayerTree()
  266. ->ScheduleCALayer(params);
  267. }
  268. bool ImageTransportSurfaceOverlayMac::IsSurfaceless() const {
  269. return true;
  270. }
  271. gfx::SurfaceOrigin ImageTransportSurfaceOverlayMac::GetOrigin() const {
  272. return gfx::SurfaceOrigin::kTopLeft;
  273. }
  274. bool ImageTransportSurfaceOverlayMac::Resize(const gfx::Size& pixel_size,
  275. float scale_factor,
  276. const gfx::ColorSpace& color_space,
  277. bool has_alpha) {
  278. pixel_size_ = pixel_size;
  279. scale_factor_ = scale_factor;
  280. ca_layer_tree_coordinator_->Resize(pixel_size, scale_factor);
  281. return true;
  282. }
  283. void ImageTransportSurfaceOverlayMac::OnGpuSwitched(
  284. gl::GpuPreference active_gpu_heuristic) {
  285. // Create a new context, and use the GL renderer ID that the new context gets.
  286. scoped_refptr<ui::IOSurfaceContext> context_on_new_gpu =
  287. ui::IOSurfaceContext::Get(ui::IOSurfaceContext::kCALayerContext);
  288. if (!context_on_new_gpu)
  289. return;
  290. GLint context_renderer_id = -1;
  291. if (CGLGetParameter(context_on_new_gpu->cgl_context(),
  292. kCGLCPCurrentRendererID,
  293. &context_renderer_id) != kCGLNoError) {
  294. LOG(ERROR) << "Failed to create test context after GPU switch";
  295. return;
  296. }
  297. gl_renderer_id_ = context_renderer_id & kCGLRendererIDMatchingMask;
  298. // Delay releasing the reference to the new GL context. The reason for this
  299. // is to avoid creating-then-destroying the context for every image transport
  300. // surface that is observing the GPU switch.
  301. base::ThreadTaskRunnerHandle::Get()->ReleaseSoon(
  302. FROM_HERE, std::move(context_on_new_gpu));
  303. }
  304. void ImageTransportSurfaceOverlayMac::SetCALayerErrorCode(
  305. gfx::CALayerResult ca_layer_error_code) {
  306. ca_layer_error_code_ = ca_layer_error_code;
  307. }
  308. #if defined(USE_EGL)
  309. ImageTransportSurfaceOverlayMacEGL::ImageTransportSurfaceOverlayMacEGL(
  310. gl::GLDisplayEGL* display,
  311. base::WeakPtr<ImageTransportSurfaceDelegate> delegate)
  312. : gl::GLSurfaceEGL(display),
  313. delegate_(delegate),
  314. use_remote_layer_api_(ui::RemoteLayerAPISupported()),
  315. scale_factor_(1),
  316. gl_renderer_id_(0),
  317. weak_ptr_factory_(this) {
  318. ui::GpuSwitchingManager::GetInstance()->AddObserver(this);
  319. static bool av_disabled_at_command_line =
  320. !base::FeatureList::IsEnabled(kAVFoundationOverlays);
  321. bool allow_av_sample_buffer_display_layer =
  322. !av_disabled_at_command_line &&
  323. !delegate_->GetFeatureInfo()
  324. ->workarounds()
  325. .disable_av_sample_buffer_display_layer;
  326. ca_layer_tree_coordinator_ = std::make_unique<ui::CALayerTreeCoordinator>(
  327. use_remote_layer_api_, allow_av_sample_buffer_display_layer);
  328. // Create the CAContext to send this to the GPU process, and the layer for
  329. // the context.
  330. if (use_remote_layer_api_) {
  331. CGSConnectionID connection_id = CGSMainConnectionID();
  332. ca_context_.reset([[CAContext contextWithCGSConnection:connection_id
  333. options:@{}] retain]);
  334. [ca_context_ setLayer:ca_layer_tree_coordinator_->GetCALayerForDisplay()];
  335. }
  336. }
  337. ImageTransportSurfaceOverlayMacEGL::~ImageTransportSurfaceOverlayMacEGL() {
  338. ui::GpuSwitchingManager::GetInstance()->RemoveObserver(this);
  339. Destroy();
  340. }
  341. bool ImageTransportSurfaceOverlayMacEGL::Initialize(
  342. gl::GLSurfaceFormat format) {
  343. return true;
  344. }
  345. void ImageTransportSurfaceOverlayMacEGL::PrepareToDestroy(bool have_context) {}
  346. void ImageTransportSurfaceOverlayMacEGL::Destroy() {
  347. ca_layer_tree_coordinator_.reset();
  348. }
  349. bool ImageTransportSurfaceOverlayMacEGL::IsOffscreen() {
  350. return false;
  351. }
  352. void ImageTransportSurfaceOverlayMacEGL::ApplyBackpressure() {
  353. TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::ApplyBackpressure");
  354. // Create the fence for the current frame before waiting on the previous
  355. // frame's fence (to maximize CPU and GPU execution overlap).
  356. gl::GLContext* current_context = gl::GLContext::GetCurrent();
  357. uint64_t this_frame_fence = current_context->BackpressureFenceCreate();
  358. current_context->BackpressureFenceWait(previous_frame_fence_);
  359. previous_frame_fence_ = this_frame_fence;
  360. }
  361. void ImageTransportSurfaceOverlayMacEGL::BufferPresented(
  362. gl::GLSurface::PresentationCallback callback,
  363. const gfx::PresentationFeedback& feedback) {
  364. DCHECK(!callback.is_null());
  365. std::move(callback).Run(feedback);
  366. }
  367. gfx::SwapResult ImageTransportSurfaceOverlayMacEGL::SwapBuffersInternal(
  368. gl::GLSurface::SwapCompletionCallback completion_callback,
  369. gl::GLSurface::PresentationCallback presentation_callback) {
  370. TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::SwapBuffersInternal");
  371. constexpr base::TimeDelta kHistogramMinTime = base::Microseconds(5);
  372. constexpr base::TimeDelta kHistogramMaxTime = base::Milliseconds(16);
  373. constexpr int kHistogramTimeBuckets = 50;
  374. // Do a GL fence for flush to apply back-pressure before drawing.
  375. {
  376. base::TimeTicks start_time = base::TimeTicks::Now();
  377. ApplyBackpressure();
  378. UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(
  379. "Gpu.Mac.BackpressureUs", base::TimeTicks::Now() - start_time,
  380. kHistogramMinTime, kHistogramMaxTime, kHistogramTimeBuckets);
  381. }
  382. // Update the CALayer tree in the GPU process.
  383. base::TimeTicks before_transaction_time = base::TimeTicks::Now();
  384. {
  385. TRACE_EVENT0("gpu", "CommitPendingTreesToCA");
  386. ca_layer_tree_coordinator_->CommitPendingTreesToCA();
  387. base::TimeDelta transaction_time =
  388. base::TimeTicks::Now() - before_transaction_time;
  389. UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(
  390. "GPU.IOSurface.CATransactionTimeUs", transaction_time,
  391. kHistogramMinTime, kHistogramMaxTime, kHistogramTimeBuckets);
  392. }
  393. // Populate the CA layer parameters to send to the browser.
  394. gfx::CALayerParams params;
  395. {
  396. TRACE_EVENT_INSTANT2("test_gpu", "SwapBuffers", TRACE_EVENT_SCOPE_THREAD,
  397. "GLImpl", static_cast<int>(gl::GetGLImplementation()),
  398. "width", pixel_size_.width());
  399. if (use_remote_layer_api_) {
  400. params.ca_context_id = [ca_context_ contextId];
  401. } else {
  402. IOSurfaceRef io_surface =
  403. ca_layer_tree_coordinator_->GetIOSurfaceForDisplay();
  404. if (io_surface) {
  405. params.io_surface_mach_port.reset(IOSurfaceCreateMachPort(io_surface));
  406. }
  407. }
  408. params.pixel_size = pixel_size_;
  409. params.scale_factor = scale_factor_;
  410. params.is_empty = false;
  411. }
  412. // Send the swap parameters to the browser.
  413. if (completion_callback) {
  414. base::ThreadTaskRunnerHandle::Get()->PostTask(
  415. FROM_HERE,
  416. base::BindOnce(std::move(completion_callback),
  417. gfx::SwapCompletionResult(
  418. gfx::SwapResult::SWAP_ACK,
  419. std::make_unique<gfx::CALayerParams>(params))));
  420. }
  421. gfx::PresentationFeedback feedback(base::TimeTicks::Now(), base::Hertz(60),
  422. /*flags=*/0);
  423. feedback.ca_layer_error_code = ca_layer_error_code_;
  424. base::ThreadTaskRunnerHandle::Get()->PostTask(
  425. FROM_HERE,
  426. base::BindOnce(&ImageTransportSurfaceOverlayMacEGL::BufferPresented,
  427. weak_ptr_factory_.GetWeakPtr(),
  428. std::move(presentation_callback), feedback));
  429. return gfx::SwapResult::SWAP_ACK;
  430. }
  431. gfx::SwapResult ImageTransportSurfaceOverlayMacEGL::SwapBuffers(
  432. gl::GLSurface::PresentationCallback callback) {
  433. return SwapBuffersInternal(base::DoNothing(), std::move(callback));
  434. }
  435. void ImageTransportSurfaceOverlayMacEGL::SwapBuffersAsync(
  436. gl::GLSurface::SwapCompletionCallback completion_callback,
  437. gl::GLSurface::PresentationCallback presentation_callback) {
  438. SwapBuffersInternal(std::move(completion_callback),
  439. std::move(presentation_callback));
  440. }
  441. gfx::SwapResult ImageTransportSurfaceOverlayMacEGL::PostSubBuffer(
  442. int x,
  443. int y,
  444. int width,
  445. int height,
  446. gl::GLSurface::PresentationCallback callback) {
  447. return SwapBuffersInternal(base::DoNothing(), std::move(callback));
  448. }
  449. void ImageTransportSurfaceOverlayMacEGL::PostSubBufferAsync(
  450. int x,
  451. int y,
  452. int width,
  453. int height,
  454. gl::GLSurface::SwapCompletionCallback completion_callback,
  455. gl::GLSurface::PresentationCallback presentation_callback) {
  456. SwapBuffersInternal(std::move(completion_callback),
  457. std::move(presentation_callback));
  458. }
  459. gfx::SwapResult ImageTransportSurfaceOverlayMacEGL::CommitOverlayPlanes(
  460. gl::GLSurface::PresentationCallback callback) {
  461. return SwapBuffersInternal(base::DoNothing(), std::move(callback));
  462. }
  463. void ImageTransportSurfaceOverlayMacEGL::CommitOverlayPlanesAsync(
  464. gl::GLSurface::SwapCompletionCallback completion_callback,
  465. gl::GLSurface::PresentationCallback presentation_callback) {
  466. SwapBuffersInternal(std::move(completion_callback),
  467. std::move(presentation_callback));
  468. }
  469. bool ImageTransportSurfaceOverlayMacEGL::SupportsPostSubBuffer() {
  470. return true;
  471. }
  472. bool ImageTransportSurfaceOverlayMacEGL::SupportsCommitOverlayPlanes() {
  473. return true;
  474. }
  475. bool ImageTransportSurfaceOverlayMacEGL::SupportsAsyncSwap() {
  476. return true;
  477. }
  478. gfx::Size ImageTransportSurfaceOverlayMacEGL::GetSize() {
  479. return gfx::Size();
  480. }
  481. void* ImageTransportSurfaceOverlayMacEGL::GetHandle() {
  482. return nullptr;
  483. }
  484. gl::GLSurfaceFormat ImageTransportSurfaceOverlayMacEGL::GetFormat() {
  485. return gl::GLSurfaceFormat();
  486. }
  487. bool ImageTransportSurfaceOverlayMacEGL::OnMakeCurrent(gl::GLContext* context) {
  488. // Ensure that the context is on the appropriate GL renderer. The GL renderer
  489. // will generally only change when the GPU changes.
  490. if (gl_renderer_id_ && context)
  491. context->share_group()->SetRendererID(gl_renderer_id_);
  492. return true;
  493. }
  494. bool ImageTransportSurfaceOverlayMacEGL::ScheduleOverlayPlane(
  495. gl::GLImage* image,
  496. std::unique_ptr<gfx::GpuFence> gpu_fence,
  497. const gfx::OverlayPlaneData& overlay_plane_data) {
  498. if (overlay_plane_data.plane_transform != gfx::OVERLAY_TRANSFORM_NONE) {
  499. DLOG(ERROR) << "Invalid overlay plane transform.";
  500. return false;
  501. }
  502. if (overlay_plane_data.z_order) {
  503. DLOG(ERROR) << "Invalid non-zero Z order.";
  504. return false;
  505. }
  506. gl::GLImageIOSurface* io_surface_image =
  507. gl::GLImageIOSurface::FromGLImage(image);
  508. if (!io_surface_image) {
  509. DLOG(ERROR) << "Not an IOSurface image.";
  510. return false;
  511. }
  512. // TODO(1290313): the display_bounds might not need to be rounded to the
  513. // nearest rect as this eventually gets made into a CALayer. CALayers work in
  514. // floats.
  515. const ui::CARendererLayerParams overlay_as_calayer_params(
  516. false, // is_clipped
  517. gfx::Rect(), // clip_rect
  518. gfx::RRectF(), // rounded_corner_bounds
  519. 0, // sorting_context_id
  520. gfx::Transform(), image,
  521. overlay_plane_data.crop_rect, // contents_rect
  522. gfx::ToNearestRect(overlay_plane_data.display_bounds), // rect
  523. SK_ColorTRANSPARENT, // background_color
  524. 0, // edge_aa_mask
  525. 1.f, // opacity
  526. GL_LINEAR, // filter
  527. absl::nullopt, // hdr_metadata
  528. gfx::ProtectedVideoType::kClear); // protected_video_type
  529. return ca_layer_tree_coordinator_->GetPendingCARendererLayerTree()
  530. ->ScheduleCALayer(overlay_as_calayer_params);
  531. }
  532. bool ImageTransportSurfaceOverlayMacEGL::ScheduleCALayer(
  533. const ui::CARendererLayerParams& params) {
  534. if (params.image) {
  535. gl::GLImageIOSurface* io_surface_image =
  536. gl::GLImageIOSurface::FromGLImage(params.image);
  537. if (!io_surface_image) {
  538. DLOG(ERROR) << "Cannot schedule CALayer with non-IOSurface GLImage";
  539. return false;
  540. }
  541. }
  542. return ca_layer_tree_coordinator_->GetPendingCARendererLayerTree()
  543. ->ScheduleCALayer(params);
  544. }
  545. bool ImageTransportSurfaceOverlayMacEGL::IsSurfaceless() const {
  546. return true;
  547. }
  548. gfx::SurfaceOrigin ImageTransportSurfaceOverlayMacEGL::GetOrigin() const {
  549. return gfx::SurfaceOrigin::kTopLeft;
  550. }
  551. bool ImageTransportSurfaceOverlayMacEGL::Resize(
  552. const gfx::Size& pixel_size,
  553. float scale_factor,
  554. const gfx::ColorSpace& color_space,
  555. bool has_alpha) {
  556. pixel_size_ = pixel_size;
  557. scale_factor_ = scale_factor;
  558. ca_layer_tree_coordinator_->Resize(pixel_size, scale_factor);
  559. return true;
  560. }
  561. void ImageTransportSurfaceOverlayMacEGL::OnGpuSwitched(
  562. gl::GpuPreference active_gpu_heuristic) {
  563. // Create a new context, and use the GL renderer ID that the new context gets.
  564. scoped_refptr<ui::IOSurfaceContext> context_on_new_gpu =
  565. ui::IOSurfaceContext::Get(ui::IOSurfaceContext::kCALayerContext);
  566. if (!context_on_new_gpu)
  567. return;
  568. GLint context_renderer_id = -1;
  569. if (CGLGetParameter(context_on_new_gpu->cgl_context(),
  570. kCGLCPCurrentRendererID,
  571. &context_renderer_id) != kCGLNoError) {
  572. LOG(ERROR) << "Failed to create test context after GPU switch";
  573. return;
  574. }
  575. gl_renderer_id_ = context_renderer_id & kCGLRendererIDMatchingMask;
  576. // Delay releasing the reference to the new GL context. The reason for this
  577. // is to avoid creating-then-destroying the context for every image transport
  578. // surface that is observing the GPU switch.
  579. base::ThreadTaskRunnerHandle::Get()->ReleaseSoon(
  580. FROM_HERE, std::move(context_on_new_gpu));
  581. }
  582. void ImageTransportSurfaceOverlayMacEGL::SetCALayerErrorCode(
  583. gfx::CALayerResult ca_layer_error_code) {
  584. ca_layer_error_code_ = ca_layer_error_code;
  585. }
  586. #endif // USE_EGL
  587. } // namespace gpu