File: gl_display_egl.mm

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (145 lines) | stat: -rw-r--r-- 5,896 bytes parent folder | download | duplicates (9)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/gl/gl_display.h"

#import <Metal/Metal.h>

#include "base/apple/scoped_nsobject.h"
#include "ui/gl/gl_bindings.h"

// From ANGLE's egl/eglext_angle.h.
#ifndef EGL_ANGLE_metal_shared_event_sync
#define EGL_ANGLE_metal_hared_event_sync 1
#define EGL_SYNC_METAL_SHARED_EVENT_ANGLE 0x34D8
#define EGL_SYNC_METAL_SHARED_EVENT_OBJECT_ANGLE 0x34D9
#define EGL_SYNC_METAL_SHARED_EVENT_SIGNAL_VALUE_LO_ANGLE 0x34DA
#define EGL_SYNC_METAL_SHARED_EVENT_SIGNAL_VALUE_HI_ANGLE 0x34DB
#define EGL_SYNC_METAL_SHARED_EVENT_SIGNALED_ANGLE 0x34DC
#endif

namespace gl {

struct GLDisplayEGL::ObjCStorage {
  base::apple::scoped_nsprotocol<id<MTLSharedEvent>> metal_shared_event;
  uint64_t metal_signaled_value = 0;
};

// Because on Apple platforms there is a member variable of a type (ObjCStorage)
// that is defined in this file, the constructor/destructor also have to be
// here. If making changes to this copy, be sure to adjust the other copy in
// gl_display.cc.
GLDisplayEGL::GLDisplayEGL(uint64_t system_device_id, DisplayKey display_key)
    : GLDisplay(system_device_id, display_key, EGL) {
  ext = std::make_unique<DisplayExtensionsEGL>();
}

GLDisplayEGL::~GLDisplayEGL() = default;

bool GLDisplayEGL::CreateMetalSharedEvent(id<MTLSharedEvent>* shared_event_out,
                                          uint64_t* signal_value_out) {
  CHECK(ext->b_EGL_ANGLE_metal_shared_event_sync);
  if (!objc_storage_->metal_shared_event) {
    std::vector<EGLAttrib> attribs;
    attribs.push_back(EGL_SYNC_METAL_SHARED_EVENT_SIGNAL_VALUE_LO_ANGLE);
    attribs.push_back(0);
    attribs.push_back(EGL_SYNC_METAL_SHARED_EVENT_SIGNAL_VALUE_HI_ANGLE);
    attribs.push_back(0);
    attribs.push_back(EGL_NONE);
    EGLSync sync =
        eglCreateSync(display_, EGL_SYNC_METAL_SHARED_EVENT_ANGLE, &attribs[0]);
    if (!sync)
      return false;

    // eglCopyMetalSharedEventANGLE returns an MTLSharedEvent object that has a
    // retain count of 1.
    objc_storage_->metal_shared_event.reset(static_cast<id<MTLSharedEvent>>(
        eglCopyMetalSharedEventANGLE(display_, sync)));

    // The sync object is already enqueued for signaling in ANGLE's command
    // stream. Since the MTLSharedEvent is already retained, it's safe to delete
    // the sync object immediately.
    eglDestroySync(display_, sync);
  }

  // Create another sync object, perhaps redundantly the first time,
  // but with our specified signal value.
  ++objc_storage_->metal_signaled_value;
  id<MTLSharedEvent> shared_event = objc_storage_->metal_shared_event.get();
  std::vector<EGLAttrib> attribs;
  attribs.push_back(EGL_SYNC_METAL_SHARED_EVENT_OBJECT_ANGLE);
  attribs.push_back(
      static_cast<EGLAttrib>(reinterpret_cast<uintptr_t>(shared_event)));
  attribs.push_back(EGL_SYNC_METAL_SHARED_EVENT_SIGNAL_VALUE_LO_ANGLE);
  attribs.push_back(objc_storage_->metal_signaled_value & 0xFFFFFFFF);
  attribs.push_back(EGL_SYNC_METAL_SHARED_EVENT_SIGNAL_VALUE_HI_ANGLE);
  attribs.push_back((objc_storage_->metal_signaled_value >> 32) & 0xFFFFFFFF);
  attribs.push_back(EGL_NONE);

  EGLSync sync =
      eglCreateSync(display_, EGL_SYNC_METAL_SHARED_EVENT_ANGLE, &attribs[0]);
  if (!sync)
    return false;

  // The sync object is already enqueued for signaling in ANGLE's command
  // stream. Since the MTLSharedEvent is already retained, it's safe to delete
  // the sync object immediately.
  eglDestroySync(display_, sync);

  *shared_event_out = objc_storage_->metal_shared_event.get();
  *signal_value_out = objc_storage_->metal_signaled_value;
  return true;
}

void GLDisplayEGL::WaitForMetalSharedEvent(id<MTLSharedEvent> shared_event,
                                           uint64_t signal_value) {
  CHECK(objc_storage_);
  if (objc_storage_->metal_shared_event.get() == shared_event) {
    // If the event is owned by this display, skip the wait.
    // Currently ANGLE/Metal is only single threaded. There is no need to issue
    // a GPU wait for an event that was signaled by the same display. Because
    // the works before and after the signal belong to the same metal queue
    // hence they are already synchronized with each other implicitly.
    CHECK_GE(objc_storage_->metal_signaled_value, signal_value);
    return;
  }

  CHECK(ext->b_EGL_ANGLE_metal_shared_event_sync);
  EGLAttrib attribs[] = {
      // Pass the Metal shared event as an EGLAttrib.
      EGL_SYNC_METAL_SHARED_EVENT_OBJECT_ANGLE,
      static_cast<EGLAttrib>(reinterpret_cast<uintptr_t>(shared_event)),
      // EGL_SYNC_METAL_SHARED_EVENT_SIGNALED_ANGLE is important as it requests
      // ANGLE to create an EGL sync object from the Metal shared event, but NOT
      // signal it to the specified value. The shared event is imported with
      // that signal value. The next call to eglWaitSync enqueue's a GPU wait to
      // wait for that value to be signaled by another command buffer.
      EGL_SYNC_CONDITION,
      EGL_SYNC_METAL_SHARED_EVENT_SIGNALED_ANGLE,
      // Encode the signaled value in two EGLAttribs.
      EGL_SYNC_METAL_SHARED_EVENT_SIGNAL_VALUE_LO_ANGLE,
      EGLAttrib(signal_value & 0xFFFFFFFF),
      EGL_SYNC_METAL_SHARED_EVENT_SIGNAL_VALUE_HI_ANGLE,
      EGLAttrib((signal_value >> 32) & 0xFFFFFFFF),
      EGL_NONE,
  };

  EGLSync sync =
      eglCreateSync(display_, EGL_SYNC_METAL_SHARED_EVENT_ANGLE, attribs);
  EGLBoolean res = eglWaitSync(display_, sync, 0);
  DCHECK(res == EGL_TRUE);
  // The wait on the sync object has been enqueued already, so it's safe to
  // destroy it now.
  eglDestroySync(display_, sync);
}

void GLDisplayEGL::InitMetalSharedEventStorage() {
  objc_storage_ = std::make_unique<ObjCStorage>();
}

void GLDisplayEGL::CleanupMetalSharedEventStorage() {
  objc_storage_.reset();
}

}  // namespace gl