display.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. // Copyright (c) 2012 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/gles2_conform_support/egl/display.h"
  5. #include <memory>
  6. #include "build/build_config.h"
  7. #include "gpu/gles2_conform_support/egl/config.h"
  8. #include "gpu/gles2_conform_support/egl/context.h"
  9. #include "gpu/gles2_conform_support/egl/surface.h"
  10. #include "gpu/gles2_conform_support/egl/thread_state.h"
  11. #include "ui/gl/gl_display.h"
  12. #include "ui/gl/gl_utils.h"
  13. #include "ui/gl/init/gl_factory.h"
  14. namespace gles2_conform_support {
  15. namespace egl {
  16. Display::Display()
  17. : is_initialized_(false),
  18. next_create_window_surface_creates_pbuffer_(false),
  19. window_surface_pbuffer_width_(0),
  20. window_surface_pbuffer_height_(0) {}
  21. Display::~Display() {
  22. surfaces_.clear();
  23. contexts_.clear();
  24. }
  25. void Display::SetNextCreateWindowSurfaceCreatesPBuffer(EGLint width,
  26. EGLint height) {
  27. next_create_window_surface_creates_pbuffer_ = true;
  28. window_surface_pbuffer_width_ = width;
  29. window_surface_pbuffer_height_ = height;
  30. }
  31. EGLBoolean Display::Initialize(ThreadState* ts, EGLint* major, EGLint* minor) {
  32. base::AutoLock auto_lock(lock_);
  33. is_initialized_ = true;
  34. if (major)
  35. *major = 1;
  36. if (minor)
  37. *minor = 4;
  38. return ts->ReturnSuccess(EGL_TRUE);
  39. }
  40. EGLBoolean Display::Terminate(ThreadState* ts) {
  41. base::AutoLock auto_lock(lock_);
  42. is_initialized_ = false;
  43. surfaces_.clear();
  44. for (const auto& context : contexts_)
  45. context->MarkDestroyed();
  46. contexts_.clear();
  47. return ts->ReturnSuccess(EGL_TRUE);
  48. }
  49. const char* Display::QueryString(ThreadState* ts, EGLint name) {
  50. base::AutoLock auto_lock(lock_);
  51. if (!is_initialized_)
  52. return ts->ReturnError<const char*>(EGL_NOT_INITIALIZED, nullptr);
  53. switch (name) {
  54. case EGL_CLIENT_APIS:
  55. return ts->ReturnSuccess("OpenGL_ES");
  56. case EGL_EXTENSIONS:
  57. return ts->ReturnSuccess("");
  58. case EGL_VENDOR:
  59. return ts->ReturnSuccess("Google LLC");
  60. case EGL_VERSION:
  61. return ts->ReturnSuccess("1.4");
  62. default:
  63. return ts->ReturnError<const char*>(EGL_BAD_PARAMETER, nullptr);
  64. }
  65. }
  66. EGLBoolean Display::ChooseConfig(ThreadState* ts,
  67. const EGLint* attrib_list,
  68. EGLConfig* configs,
  69. EGLint config_size,
  70. EGLint* num_config) {
  71. base::AutoLock auto_lock(lock_);
  72. if (!is_initialized_)
  73. return ts->ReturnError(EGL_NOT_INITIALIZED, EGL_FALSE);
  74. if (num_config == nullptr)
  75. return ts->ReturnError(EGL_BAD_PARAMETER, EGL_FALSE);
  76. if (!Config::ValidateAttributeList(attrib_list))
  77. return ts->ReturnError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
  78. InitializeConfigsIfNeeded();
  79. if (!configs)
  80. config_size = 0;
  81. *num_config = 0;
  82. for (size_t i = 0; i < std::size(configs_); ++i) {
  83. if (configs_[i]->Matches(attrib_list)) {
  84. if (*num_config < config_size) {
  85. configs[*num_config] = configs_[i].get();
  86. }
  87. ++*num_config;
  88. }
  89. }
  90. return ts->ReturnSuccess(EGL_TRUE);
  91. }
  92. EGLBoolean Display::GetConfigs(ThreadState* ts,
  93. EGLConfig* configs,
  94. EGLint config_size,
  95. EGLint* num_config) {
  96. base::AutoLock auto_lock(lock_);
  97. if (!is_initialized_)
  98. return ts->ReturnError(EGL_NOT_INITIALIZED, EGL_FALSE);
  99. if (num_config == nullptr)
  100. return ts->ReturnError(EGL_BAD_PARAMETER, EGL_FALSE);
  101. InitializeConfigsIfNeeded();
  102. if (!configs)
  103. config_size = 0;
  104. *num_config = std::size(configs_);
  105. size_t count =
  106. std::min(std::size(configs_), static_cast<size_t>(config_size));
  107. for (size_t i = 0; i < count; ++i)
  108. configs[i] = configs_[i].get();
  109. return ts->ReturnSuccess(EGL_TRUE);
  110. }
  111. bool Display::IsValidNativeWindow(EGLNativeWindowType win) {
  112. #if BUILDFLAG(IS_WIN)
  113. return ::IsWindow(win) != FALSE;
  114. #else
  115. // TODO(alokp): Validate window handle.
  116. return true;
  117. #endif // BUILDFLAG(IS_WIN)
  118. }
  119. EGLBoolean Display::GetConfigAttrib(ThreadState* ts,
  120. EGLConfig cfg,
  121. EGLint attribute,
  122. EGLint* value) {
  123. base::AutoLock auto_lock(lock_);
  124. if (!is_initialized_)
  125. return ts->ReturnError(EGL_NOT_INITIALIZED, EGL_FALSE);
  126. const egl::Config* config = GetConfig(cfg);
  127. if (!config)
  128. return ts->ReturnError(EGL_BAD_CONFIG, EGL_FALSE);
  129. if (!config->GetAttrib(attribute, value))
  130. return ts->ReturnError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
  131. return ts->ReturnSuccess(EGL_TRUE);
  132. }
  133. EGLSurface Display::CreatePbufferSurface(ThreadState* ts,
  134. EGLConfig cfg,
  135. const EGLint* attrib_list) {
  136. base::AutoLock auto_lock(lock_);
  137. if (!is_initialized_)
  138. return ts->ReturnError(EGL_NOT_INITIALIZED, EGL_NO_SURFACE);
  139. const egl::Config* config = GetConfig(cfg);
  140. if (!config)
  141. return ts->ReturnError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
  142. EGLint value = EGL_NONE;
  143. config->GetAttrib(EGL_SURFACE_TYPE, &value);
  144. if ((value & EGL_PBUFFER_BIT) == 0)
  145. return ts->ReturnError(EGL_BAD_MATCH, EGL_NO_SURFACE);
  146. if (!egl::Surface::ValidatePbufferAttributeList(attrib_list))
  147. return ts->ReturnError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
  148. int width = 1;
  149. int height = 1;
  150. if (attrib_list) {
  151. for (const int32_t* attr = attrib_list; attr[0] != EGL_NONE; attr += 2) {
  152. switch (attr[0]) {
  153. case EGL_WIDTH:
  154. width = attr[1];
  155. break;
  156. case EGL_HEIGHT:
  157. height = attr[1];
  158. break;
  159. }
  160. }
  161. }
  162. return DoCreatePbufferSurface(ts, config, width, height);
  163. }
  164. EGLSurface Display::DoCreatePbufferSurface(ThreadState* ts,
  165. const Config* config,
  166. EGLint width,
  167. EGLint height) {
  168. lock_.AssertAcquired();
  169. scoped_refptr<gl::GLSurface> gl_surface;
  170. gl_surface = gl::init::CreateOffscreenGLSurface(gl::GetDefaultDisplay(),
  171. gfx::Size(width, height));
  172. if (!gl_surface)
  173. return ts->ReturnError(EGL_BAD_ALLOC, nullptr);
  174. surfaces_.emplace_back(new Surface(gl_surface.get(), config));
  175. return ts->ReturnSuccess<EGLSurface>(surfaces_.back().get());
  176. }
  177. EGLSurface Display::CreateWindowSurface(ThreadState* ts,
  178. EGLConfig cfg,
  179. EGLNativeWindowType win,
  180. const EGLint* attrib_list) {
  181. base::AutoLock auto_lock(lock_);
  182. if (!is_initialized_)
  183. return ts->ReturnError(EGL_NOT_INITIALIZED, EGL_NO_SURFACE);
  184. const egl::Config* config = GetConfig(cfg);
  185. if (!config)
  186. return ts->ReturnError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
  187. EGLint value = EGL_NONE;
  188. config->GetAttrib(EGL_SURFACE_TYPE, &value);
  189. if ((value & EGL_WINDOW_BIT) == 0)
  190. return ts->ReturnError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
  191. if (!next_create_window_surface_creates_pbuffer_ && !IsValidNativeWindow(win))
  192. return ts->ReturnError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
  193. if (!Surface::ValidateWindowAttributeList(attrib_list))
  194. return ts->ReturnError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
  195. if (next_create_window_surface_creates_pbuffer_) {
  196. EGLSurface result = DoCreatePbufferSurface(ts, config,
  197. window_surface_pbuffer_width_,
  198. window_surface_pbuffer_height_);
  199. next_create_window_surface_creates_pbuffer_ = false;
  200. window_surface_pbuffer_width_ = 0;
  201. window_surface_pbuffer_height_ = 0;
  202. return result;
  203. }
  204. scoped_refptr<gl::GLSurface> gl_surface;
  205. #if BUILDFLAG(IS_MAC)
  206. gfx::AcceleratedWidget widget = gfx::kNullAcceleratedWidget;
  207. #else
  208. gfx::AcceleratedWidget widget = static_cast<gfx::AcceleratedWidget>(win);
  209. #endif
  210. gl_surface = gl::init::CreateViewGLSurface(gl::GetDefaultDisplay(), widget);
  211. if (!gl_surface)
  212. return ts->ReturnError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
  213. surfaces_.emplace_back(new Surface(gl_surface.get(), config));
  214. return ts->ReturnSuccess(surfaces_.back().get());
  215. }
  216. EGLBoolean Display::DestroySurface(ThreadState* ts, EGLSurface sfe) {
  217. base::AutoLock auto_lock(lock_);
  218. if (!is_initialized_)
  219. return ts->ReturnError(EGL_NOT_INITIALIZED, EGL_FALSE);
  220. auto it = std::find(surfaces_.begin(), surfaces_.end(), sfe);
  221. if (it == surfaces_.end())
  222. return ts->ReturnError(EGL_BAD_SURFACE, EGL_FALSE);
  223. surfaces_.erase(it);
  224. return ts->ReturnSuccess(EGL_TRUE);
  225. }
  226. EGLBoolean Display::ReleaseCurrent(ThreadState* ts) {
  227. base::AutoLock auto_lock(lock_);
  228. if (!is_initialized_)
  229. return ts->ReturnSuccess(EGL_TRUE);
  230. ThreadState::AutoCurrentContextRestore accr(ts);
  231. if (ts->current_context()) {
  232. Context::MakeCurrent(ts->current_context(), ts->current_surface(), nullptr,
  233. nullptr);
  234. accr.SetCurrent(nullptr, nullptr);
  235. }
  236. return ts->ReturnSuccess(EGL_TRUE);
  237. }
  238. EGLBoolean Display::MakeCurrent(ThreadState* ts,
  239. EGLSurface draw,
  240. EGLSurface read,
  241. EGLSurface ctx) {
  242. base::AutoLock auto_lock(lock_);
  243. if (!is_initialized_)
  244. return ts->ReturnError(EGL_NOT_INITIALIZED, EGL_FALSE);
  245. ThreadState::AutoCurrentContextRestore accr(ts);
  246. // Client might have called use because it changed some other gl binding
  247. // global state. For example, the client might have called eglMakeCurrent on
  248. // the same EGL as what command buffer uses. The client probably knows that
  249. // this invalidates the internal state of command buffer, too. So reset the
  250. // current context with accr in any case, regardless whether context or
  251. // surface pointer changes.
  252. Surface* new_surface = GetSurface(draw);
  253. if (!new_surface)
  254. return ts->ReturnError(EGL_BAD_SURFACE, EGL_FALSE);
  255. new_surface = GetSurface(read);
  256. if (!new_surface)
  257. return ts->ReturnError(EGL_BAD_SURFACE, EGL_FALSE);
  258. egl::Context* new_context = GetContext(ctx);
  259. if (!new_context)
  260. return ts->ReturnError(EGL_BAD_CONTEXT, EGL_FALSE);
  261. if (draw != read)
  262. return ts->ReturnError(EGL_BAD_MATCH, EGL_FALSE);
  263. Surface* current_surface = ts->current_surface();
  264. Context* current_context = ts->current_context();
  265. if (current_context != new_context &&
  266. new_context->is_current_in_some_thread())
  267. return ts->ReturnError(EGL_BAD_ACCESS, EGL_FALSE);
  268. if (current_surface != new_surface &&
  269. new_surface->is_current_in_some_thread())
  270. return ts->ReturnError(EGL_BAD_ACCESS, EGL_FALSE);
  271. if (!Context::MakeCurrent(current_context,
  272. current_context ? current_surface : nullptr,
  273. new_context, new_context ? new_surface : nullptr))
  274. return ts->ReturnError(EGL_BAD_MATCH, EGL_FALSE);
  275. accr.SetCurrent(new_surface, new_context);
  276. return ts->ReturnSuccess(EGL_TRUE);
  277. }
  278. EGLBoolean Display::SwapBuffers(ThreadState* ts, EGLSurface sfe) {
  279. base::AutoLock auto_lock(lock_);
  280. if (!is_initialized_)
  281. return ts->ReturnError(EGL_NOT_INITIALIZED, EGL_FALSE);
  282. egl::Surface* surface = GetSurface(sfe);
  283. if (!surface)
  284. return ts->ReturnError(EGL_BAD_SURFACE, EGL_FALSE);
  285. if (ts->current_surface() != surface)
  286. return ts->ReturnError(EGL_BAD_SURFACE, EGL_FALSE);
  287. if (!ts->current_context()->SwapBuffers(surface))
  288. ts->ReturnError(EGL_CONTEXT_LOST, EGL_FALSE);
  289. return ts->ReturnSuccess(EGL_TRUE);
  290. }
  291. EGLContext Display::CreateContext(ThreadState* ts,
  292. EGLConfig cfg,
  293. EGLContext share_ctx,
  294. const EGLint* attrib_list) {
  295. base::AutoLock auto_lock(lock_);
  296. if (!is_initialized_)
  297. return ts->ReturnError(EGL_NOT_INITIALIZED, EGL_NO_CONTEXT);
  298. if (share_ctx != EGL_NO_CONTEXT) {
  299. egl::Context* share_context = GetContext(share_ctx);
  300. if (!share_context)
  301. return ts->ReturnError(EGL_BAD_CONTEXT, EGL_NO_CONTEXT);
  302. // TODO(alokp): Add support for shared contexts.
  303. return ts->ReturnError(EGL_BAD_MATCH, EGL_NO_CONTEXT);
  304. }
  305. if (!egl::Context::ValidateAttributeList(attrib_list))
  306. return ts->ReturnError(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
  307. const egl::Config* config = GetConfig(cfg);
  308. if (!config)
  309. return ts->ReturnError(EGL_BAD_CONFIG, EGL_NO_CONTEXT);
  310. scoped_refptr<Context> context(new Context(this, config));
  311. if (!context)
  312. return ts->ReturnError(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
  313. contexts_.emplace_back(context.get());
  314. return ts->ReturnSuccess<EGLContext>(context.get());
  315. }
  316. EGLBoolean Display::DestroyContext(ThreadState* ts, EGLContext ctx) {
  317. base::AutoLock auto_lock(lock_);
  318. if (!is_initialized_)
  319. return ts->ReturnError(EGL_NOT_INITIALIZED, EGL_FALSE);
  320. auto it = std::find(contexts_.begin(), contexts_.end(), ctx);
  321. if (it == contexts_.end())
  322. return ts->ReturnError(EGL_BAD_CONTEXT, EGL_FALSE);
  323. (*it)->MarkDestroyed();
  324. contexts_.erase(it);
  325. return ts->ReturnSuccess(EGL_TRUE);
  326. }
  327. uint64_t Display::GenerateFenceSyncRelease() {
  328. base::AutoLock auto_lock(lock_);
  329. return next_fence_sync_release_++;
  330. }
  331. void Display::InitializeConfigsIfNeeded() {
  332. lock_.AssertAcquired();
  333. if (!configs_[0]) {
  334. // The interface offers separate configs for window and pbuffer.
  335. // This way we can record the client intention at context creation time.
  336. // The GL implementation (gl::GLContext and gl::GLSurface) needs this
  337. // distinction when creating a context.
  338. configs_[0] = std::make_unique<Config>(EGL_WINDOW_BIT);
  339. configs_[1] = std::make_unique<Config>(EGL_PBUFFER_BIT);
  340. }
  341. }
  342. const Config* Display::GetConfig(EGLConfig cfg) {
  343. lock_.AssertAcquired();
  344. for (const auto& config : configs_) {
  345. if (config.get() == cfg)
  346. return config.get();
  347. }
  348. return nullptr;
  349. }
  350. Surface* Display::GetSurface(EGLSurface surface) {
  351. lock_.AssertAcquired();
  352. auto it = std::find(surfaces_.begin(), surfaces_.end(), surface);
  353. if (it == surfaces_.end())
  354. return nullptr;
  355. return it->get();
  356. }
  357. Context* Display::GetContext(EGLContext context) {
  358. lock_.AssertAcquired();
  359. auto it = std::find(contexts_.begin(), contexts_.end(), context);
  360. if (it == contexts_.end())
  361. return nullptr;
  362. return it->get();
  363. }
  364. } // namespace egl
  365. } // namespace gles2_conform_support