1 // Copyright (c) 2016 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 
5 #include "gpu/gles2_conform_support/egl/context.h"
6 
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/command_line.h"
10 #include "gpu/command_buffer/client/gles2_implementation.h"
11 #include "gpu/command_buffer/client/gles2_lib.h"
12 #include "gpu/command_buffer/client/shared_memory_limits.h"
13 #include "gpu/command_buffer/client/transfer_buffer.h"
14 #include "gpu/command_buffer/service/context_group.h"
15 #include "gpu/command_buffer/service/image_manager.h"
16 #include "gpu/command_buffer/service/memory_tracking.h"
17 #include "gpu/command_buffer/service/service_discardable_manager.h"
18 #include "gpu/command_buffer/service/shared_image_manager.h"
19 #include "gpu/gles2_conform_support/egl/config.h"
20 #include "gpu/gles2_conform_support/egl/display.h"
21 #include "gpu/gles2_conform_support/egl/surface.h"
22 #include "gpu/gles2_conform_support/egl/thread_state.h"
23 #include "ui/gl/init/gl_factory.h"
24 
25 // The slight complexification in this file comes from following properties:
26 // 1) Command buffer connection (context) can not be established without a
27 // GLSurface. EGL Context can be created independent of a surface.  This is why
28 // the connection is created only during first MakeCurrent.
29 // 2) Command buffer MakeCurrent calls need the real gl context and surface be
30 // current.
31 // 3) Client can change real EGL context behind the scenes and then still expect
32 // command buffer MakeCurrent re-set the command buffer context. This is why all
33 // MakeCurrent calls must actually reset the real context, even though command
34 // buffer current context does not change.
35 // 4) EGL context can be destroyed without surface, but command buffer would
36 // need the surface to run various cleanups. If context is destroyed
37 // surfaceless, the context is marked lost before destruction. This is avoided
38 // if possible, since command buffer at the time of writing prints out debug
39 // text in this case.
40 
41 namespace {
42 const bool kBindGeneratesResources = true;
43 const bool kLoseContextWhenOutOfMemory = false;
44 const bool kSupportClientSideArrays = true;
45 }
46 
47 namespace egl {
48 // static
49 gpu::GpuFeatureInfo Context::platform_gpu_feature_info_;
50 
51 // static
SetPlatformGpuFeatureInfo(const gpu::GpuFeatureInfo & gpu_feature_info)52 void Context::SetPlatformGpuFeatureInfo(
53     const gpu::GpuFeatureInfo& gpu_feature_info) {
54   platform_gpu_feature_info_ = gpu_feature_info;
55 }
56 
Context(Display * display,const Config * config)57 Context::Context(Display* display, const Config* config)
58     : display_(display),
59       config_(config),
60       is_current_in_some_thread_(false),
61       is_destroyed_(false),
62       gpu_driver_bug_workarounds_(
63           platform_gpu_feature_info_.enabled_gpu_driver_bug_workarounds),
64       discardable_manager_(gpu::GpuPreferences()),
65       passthrough_discardable_manager_(gpu::GpuPreferences()),
66       translator_cache_(gpu::GpuPreferences()) {}
67 
~Context()68 Context::~Context() {
69   // We might not have a surface, so we must lose the context.  Cleanup will
70   // execute GL commands otherwise. TODO: if shared contexts are ever
71   // implemented, this will leak the GL resources. For pbuffer contexts, one
72   // could track the last current surface or create a surface for destroying
73   // purposes only. Other option would be to make the service usable without
74   // surface.
75   if (HasService()) {
76     if (!WasServiceContextLost())
77       MarkServiceContextLost();
78     DestroyService();
79   }
80 }
81 
MarkDestroyed()82 void Context::MarkDestroyed() {
83   is_destroyed_ = true;
84 }
85 
SwapBuffers(Surface * current_surface)86 bool Context::SwapBuffers(Surface* current_surface) {
87   DCHECK(HasService() && is_current_in_some_thread_);
88   if (WasServiceContextLost())
89     return false;
90   client_gl_context_->SwapBuffers(1);
91   return true;
92 }
93 
MakeCurrent(Context * current_context,Surface * current_surface,Context * new_context,Surface * new_surface)94 bool Context::MakeCurrent(Context* current_context,
95                           Surface* current_surface,
96                           Context* new_context,
97                           Surface* new_surface) {
98   if (!new_context && !current_context) {
99     return true;
100   }
101   bool cleanup_old_current_context = false;
102   if (current_context) {
103     if (current_context->Flush(current_surface->gl_surface()))
104       cleanup_old_current_context = new_context != current_context;
105   }
106 
107   if (new_context) {
108     if (!new_context->IsCompatibleSurface(new_surface))
109       return false;
110 
111     if (new_context->HasService()) {
112       if (new_context->WasServiceContextLost())
113         return false;
114       if (new_context != current_context) {
115         // If Flush did not set the current context, set it now. Otherwise
116         // calling into the decoder is not ok.
117         if (!new_context->gl_context_->MakeCurrent(new_surface->gl_surface())) {
118           new_context->MarkServiceContextLost();
119           return false;
120         }
121       }
122       if (new_context != current_context || new_surface != current_surface)
123         new_context->decoder_->SetSurface(new_surface->gl_surface());
124       if (!new_context->decoder_->MakeCurrent()) {
125         new_context->MarkServiceContextLost();
126         return false;
127       }
128     } else {
129       if (!new_context->CreateService(new_surface->gl_surface())) {
130         return false;
131       }
132     }
133   }
134 
135   // The current_surface will be released when MakeCurrent succeeds.
136   // Cleanup in this case only.
137   if (cleanup_old_current_context) {
138     if (current_context->is_destroyed_ && current_surface != new_surface) {
139       current_context->gl_context_->MakeCurrent(current_surface->gl_surface());
140       // If we are releasing the context and we have one ref, it means that the
141       // ref will be lost and the object will be destroyed.  Destroy the service
142       // explicitly here, so that cleanup can happen and client GL
143       // implementation does not print errors.
144       current_context->DestroyService();
145     } else {
146       current_context->decoder_->ReleaseSurface();
147     }
148   }
149 
150   return true;
151 }
152 
ValidateAttributeList(const EGLint * attrib_list)153 bool Context::ValidateAttributeList(const EGLint* attrib_list) {
154   if (attrib_list) {
155     for (int i = 0; attrib_list[i] != EGL_NONE; attrib_list += 2) {
156       switch (attrib_list[i]) {
157         case EGL_CONTEXT_CLIENT_VERSION:
158           break;
159         default:
160           return false;
161       }
162     }
163   }
164   return true;
165 }
166 
SetGpuControlClient(gpu::GpuControlClient *)167 void Context::SetGpuControlClient(gpu::GpuControlClient*) {
168   // The client is not currently called, so don't store it.
169 }
170 
GetCapabilities() const171 const gpu::Capabilities& Context::GetCapabilities() const {
172   return capabilities_;
173 }
174 
CreateImage(ClientBuffer buffer,size_t width,size_t height)175 int32_t Context::CreateImage(ClientBuffer buffer, size_t width, size_t height) {
176   NOTREACHED();
177   return -1;
178 }
179 
DestroyImage(int32_t id)180 void Context::DestroyImage(int32_t id) {
181   NOTREACHED();
182 }
183 
SignalQuery(uint32_t query,base::OnceClosure callback)184 void Context::SignalQuery(uint32_t query, base::OnceClosure callback) {
185   NOTREACHED();
186 }
187 
CreateGpuFence(uint32_t gpu_fence_id,ClientGpuFence source)188 void Context::CreateGpuFence(uint32_t gpu_fence_id, ClientGpuFence source) {
189   NOTREACHED();
190 }
191 
GetGpuFence(uint32_t gpu_fence_id,base::OnceCallback<void (std::unique_ptr<gfx::GpuFence>)> callback)192 void Context::GetGpuFence(
193     uint32_t gpu_fence_id,
194     base::OnceCallback<void(std::unique_ptr<gfx::GpuFence>)> callback) {
195   NOTREACHED();
196 }
197 
SetLock(base::Lock *)198 void Context::SetLock(base::Lock*) {
199   NOTREACHED();
200 }
201 
EnsureWorkVisible()202 void Context::EnsureWorkVisible() {
203   NOTREACHED();
204 }
205 
GetNamespaceID() const206 gpu::CommandBufferNamespace Context::GetNamespaceID() const {
207   return gpu::CommandBufferNamespace::INVALID;
208 }
209 
GetCommandBufferID() const210 gpu::CommandBufferId Context::GetCommandBufferID() const {
211   return gpu::CommandBufferId();
212 }
213 
FlushPendingWork()214 void Context::FlushPendingWork() {
215   NOTREACHED();
216 }
217 
GenerateFenceSyncRelease()218 uint64_t Context::GenerateFenceSyncRelease() {
219   NOTREACHED();
220   return 0;
221 }
222 
IsFenceSyncReleased(uint64_t release)223 bool Context::IsFenceSyncReleased(uint64_t release) {
224   NOTREACHED();
225   return false;
226 }
227 
SignalSyncToken(const gpu::SyncToken & sync_token,base::OnceClosure callback)228 void Context::SignalSyncToken(const gpu::SyncToken& sync_token,
229                               base::OnceClosure callback) {
230   NOTREACHED();
231 }
232 
WaitSyncToken(const gpu::SyncToken & sync_token)233 void Context::WaitSyncToken(const gpu::SyncToken& sync_token) {
234   NOTREACHED();
235 }
236 
CanWaitUnverifiedSyncToken(const gpu::SyncToken & sync_token)237 bool Context::CanWaitUnverifiedSyncToken(const gpu::SyncToken& sync_token) {
238   return false;
239 }
240 
SetDisplayTransform(gfx::OverlayTransform transform)241 void Context::SetDisplayTransform(gfx::OverlayTransform transform) {
242   NOTREACHED();
243 }
244 
ApplyCurrentContext(gl::GLSurface * current_surface)245 void Context::ApplyCurrentContext(gl::GLSurface* current_surface) {
246   DCHECK(HasService());
247   // The current_surface will be the same as
248   // the surface of the decoder. We can not DCHECK as there is
249   // no accessor.
250   if (!WasServiceContextLost()) {
251     if (!gl_context_->MakeCurrent(current_surface))
252       MarkServiceContextLost();
253   }
254   gles2::SetGLContext(client_gl_context_.get());
255 }
256 
ApplyContextReleased()257 void Context::ApplyContextReleased() {
258   gles2::SetGLContext(nullptr);
259 }
260 
CreateService(gl::GLSurface * gl_surface)261 bool Context::CreateService(gl::GLSurface* gl_surface) {
262   gpu::SharedMemoryLimits limits;
263   gpu::GpuPreferences gpu_preferences;
264   gpu::GpuFeatureInfo gpu_feature_info;
265   scoped_refptr<gpu::gles2::FeatureInfo> feature_info(
266       new gpu::gles2::FeatureInfo(gpu_driver_bug_workarounds_,
267                                   gpu_feature_info));
268   scoped_refptr<gpu::gles2::ContextGroup> group(new gpu::gles2::ContextGroup(
269       gpu_preferences, true, &mailbox_manager_, nullptr /* memory_tracker */,
270       &translator_cache_, &completeness_cache_, feature_info, true,
271       &image_manager_, nullptr /* image_factory */,
272       nullptr /* progress_reporter */, gpu_feature_info, &discardable_manager_,
273       &passthrough_discardable_manager_, &shared_image_manager_));
274 
275   auto command_buffer = std::make_unique<gpu::CommandBufferDirect>();
276 
277   std::unique_ptr<gpu::gles2::GLES2Decoder> decoder(
278       gpu::gles2::GLES2Decoder::Create(command_buffer.get(),
279                                        command_buffer->service(), &outputter_,
280                                        group.get()));
281 
282   command_buffer->set_handler(decoder.get());
283 
284   gl::GLContextAttribs context_attribs;
285   context_attribs.gpu_preference = gl::GpuPreference::kHighPerformance;
286   scoped_refptr<gl::GLContext> gl_context(
287       gl::init::CreateGLContext(nullptr, gl_surface, context_attribs));
288   if (!gl_context)
289     return false;
290   platform_gpu_feature_info_.ApplyToGLContext(gl_context.get());
291 
292   gl_context->MakeCurrent(gl_surface);
293 
294   gpu::ContextCreationAttribs helper;
295   config_->GetAttrib(EGL_ALPHA_SIZE, &helper.alpha_size);
296   config_->GetAttrib(EGL_DEPTH_SIZE, &helper.depth_size);
297   config_->GetAttrib(EGL_STENCIL_SIZE, &helper.stencil_size);
298 
299   helper.buffer_preserved = false;
300   helper.bind_generates_resource = kBindGeneratesResources;
301   helper.fail_if_major_perf_caveat = false;
302   helper.lose_context_when_out_of_memory = kLoseContextWhenOutOfMemory;
303   helper.context_type = gpu::CONTEXT_TYPE_OPENGLES2;
304   helper.offscreen_framebuffer_size = gl_surface->GetSize();
305 
306   auto result = decoder->Initialize(gl_surface, gl_context.get(),
307                                     gl_surface->IsOffscreen(),
308                                     gpu::gles2::DisallowedFeatures(), helper);
309   if (result != gpu::ContextResult::kSuccess)
310     return false;
311 
312   auto gles2_cmd_helper =
313       std::make_unique<gpu::gles2::GLES2CmdHelper>(command_buffer.get());
314   result = gles2_cmd_helper->Initialize(limits.command_buffer_size);
315   if (result != gpu::ContextResult::kSuccess) {
316     decoder->Destroy(true);
317     return false;
318   }
319   // Client side Capabilities queries return reference, service side return
320   // value. Here two sides are joined together.
321   capabilities_ = decoder->GetCapabilities();
322 
323   auto transfer_buffer =
324       std::make_unique<gpu::TransferBuffer>(gles2_cmd_helper.get());
325 
326   gles2_cmd_helper_ = std::move(gles2_cmd_helper);
327   transfer_buffer_ = std::move(transfer_buffer);
328   command_buffer_ = std::move(command_buffer);
329   decoder_ = std::move(decoder);
330   gl_context_ = gl_context.get();
331 
332   auto context = std::make_unique<gpu::gles2::GLES2Implementation>(
333       gles2_cmd_helper_.get(), nullptr, transfer_buffer_.get(),
334       kBindGeneratesResources, kLoseContextWhenOutOfMemory,
335       kSupportClientSideArrays, this);
336 
337   result = context->Initialize(limits);
338   if (result != gpu::ContextResult::kSuccess) {
339     DestroyService();
340     return false;
341   }
342 
343   context->EnableFeatureCHROMIUM("pepper3d_allow_buffers_on_multiple_targets");
344   context->EnableFeatureCHROMIUM("pepper3d_support_fixed_attribs");
345   client_gl_context_ = std::move(context);
346   return true;
347 }
348 
DestroyService()349 void Context::DestroyService() {
350   DCHECK(HasService());
351   bool have_context = !WasServiceContextLost();
352   // The client gl interface might still be set to current global
353   // interface. This will be cleaned up in ApplyContextReleased
354   // with AutoCurrentContextRestore.
355   client_gl_context_.reset();
356   gl_context_ = nullptr;
357 
358   transfer_buffer_.reset();
359   gles2_cmd_helper_.reset();
360   if (decoder_)
361     decoder_->Destroy(have_context);
362   decoder_.reset();
363   command_buffer_.reset();
364 }
365 
HasService() const366 bool Context::HasService() const {
367   return decoder_ != nullptr;
368 }
369 
MarkServiceContextLost()370 void Context::MarkServiceContextLost() {
371   decoder_->GetContextGroup()->LoseContexts(gpu::error::kMakeCurrentFailed);
372 }
373 
WasServiceContextLost() const374 bool Context::WasServiceContextLost() const {
375   return decoder_->WasContextLost();
376 }
377 
IsCompatibleSurface(Surface * surface) const378 bool Context::IsCompatibleSurface(Surface* surface) const {
379   // Inspect current_surface->config() instead of gl_surface()->IsOffscreen()
380   // because GTF windowless window surfaces might be emulated with offscreen
381   // surfaces.
382   EGLint value = EGL_NONE;
383   config_->GetAttrib(EGL_SURFACE_TYPE, &value);
384   bool context_config_is_offscreen = (value & EGL_PBUFFER_BIT) != 0;
385   surface->config()->GetAttrib(EGL_SURFACE_TYPE, &value);
386   bool surface_config_is_offscreen = (value & EGL_PBUFFER_BIT) != 0;
387   return surface_config_is_offscreen == context_config_is_offscreen;
388 }
389 
Flush(gl::GLSurface * gl_surface)390 bool Context::Flush(gl::GLSurface* gl_surface) {
391   if (WasServiceContextLost())
392     return false;
393   if (!gl_context_->MakeCurrent(gl_surface)) {
394     MarkServiceContextLost();
395     return false;
396   }
397   client_gl_context_->Flush();
398   return true;
399 }
400 
401 }  // namespace egl
402