Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(53)

Side by Side Diff: gpu/gles2_conform_support/egl/context.cc

Issue 1714883002: command_buffer_gles2: Implement EGL default Display as a global object (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@command_buffer_gles2-multiple-contexts
Patch Set: win fixes Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 "gpu/command_buffer/client/gles2_implementation.h"
10 #include "gpu/command_buffer/client/gles2_lib.h"
11 #include "gpu/command_buffer/client/transfer_buffer.h"
12 #include "gpu/command_buffer/common/value_state.h"
13 #include "gpu/command_buffer/service/context_group.h"
14 #include "gpu/command_buffer/service/mailbox_manager.h"
15 #include "gpu/command_buffer/service/memory_tracking.h"
16 #include "gpu/command_buffer/service/transfer_buffer_manager.h"
17 #include "gpu/command_buffer/service/valuebuffer_manager.h"
18 #include "gpu/gles2_conform_support/egl/config.h"
19 #include "gpu/gles2_conform_support/egl/display.h"
20 #include "gpu/gles2_conform_support/egl/surface.h"
21 #include "gpu/gles2_conform_support/egl/thread_state.h"
22
23 // The slight complexification in this file comes from following properties:
24 // 1) Command buffer connection (context) can not be established without a
25 // GLSurface. EGL Context can be created independent of a surface. This is why
26 // the connection is created only during first MakeCurrent.
27 // 2) Command buffer MakeCurrent calls need the real gl context and surface be
28 // current.
29 // 3) Client can change real EGL context behind the scenes and then still expect
30 // command buffer MakeCurrent re-set the command buffer context. This is why all
31 // MakeCurrent calls must actually reset the real context, even though command
32 // buffer current context does not change.
33 // 4) EGL context can be destroyed without surface, but command buffer would
34 // need the surface to run various cleanups. If context is destroyed
35 // surfaceless, the context is marked lost before destruction. This is avoided
36 // if possible, since command buffer at the time of writing prints out debug
37 // text in this case.
38
39 namespace {
40 const int32_t kCommandBufferSize = 1024 * 1024;
41 const int32_t kTransferBufferSize = 512 * 1024;
42 const bool kBindGeneratesResources = true;
43 const bool kLoseContextWhenOutOfMemory = false;
44 const bool kSupportClientSideArrays = true;
45 }
46
47 namespace egl {
48 Context::Context(Display* display, const Config* config)
49 : display_(display), config_(config), is_current_in_some_thread_(false) {}
50
51 Context::~Context() {
52 // We might not have a surface, so we must lose the context.
piman 2016/02/23 23:37:16 If we lose the context, we will leak any resource
Kimmo Kinnunen 2016/02/24 07:33:26 .. to the extent that there ever will be "normal a
piman 2016/02/24 21:53:45 It's more a heads-up/documentation thing for somet
53 // Cleanup will execute GL commands otherwise.
54 if (HasService()) {
55 if (!WasServiceContextLost())
56 MarkServiceContextLost();
57 DestroyService();
58 }
59 }
60
61 void Context::FlushAndSwapBuffers(gfx::GLSurface* current_surface) {
62 DCHECK(HasService() && is_current_in_some_thread_);
63 if (!Flush(current_surface))
64 return;
65 current_surface->SwapBuffers();
66 }
67
68 bool Context::MakeCurrent(Context* current_context,
69 gfx::GLSurface* current_surface,
70 Context* new_context,
71 gfx::GLSurface* new_surface) {
72 if (!new_context && !current_context) {
73 return true;
74 }
75
76 bool cleanup_old_current_context = false;
77 if (current_context) {
78 if (current_context->Flush(current_surface))
79 cleanup_old_current_context = new_context != current_context;
80 }
81
82 if (new_context) {
83 if (!new_context->IsCompatibleSurface(new_surface))
84 return false;
85
86 if (new_context->HasService()) {
87 if (new_context->WasServiceContextLost())
88 return false;
89 if (new_context != current_context) {
90 // If Flush did not set the current context, set it now. Otherwise
91 // calling into the decoder is not ok.
92 if (!new_context->gl_context_->MakeCurrent(new_surface)) {
93 new_context->MarkServiceContextLost();
94 return false;
95 }
96 }
97 if (new_context != current_context || new_surface != current_surface)
98 new_context->decoder_->SetSurface(new_surface);
99 if (!new_context->decoder_->MakeCurrent()) {
100 new_context->MarkServiceContextLost();
101 return false;
102 }
103 } else {
104 if (!new_context->CreateService(new_surface)) {
105 return false;
106 }
107 }
108 }
109
110 // The current_surface will be released when MakeCurrent succeeds.
111 // Cleanup in this case only.
112 if (cleanup_old_current_context) {
113 if (current_context->HasOneRef() && current_surface != new_surface) {
piman 2016/02/23 23:37:16 I'm somewhat uncomfortable with HasOneRef(), becau
Kimmo Kinnunen 2016/02/24 07:33:26 Done.
114 current_context->gl_context_->MakeCurrent(current_surface);
115 // If we are releasing the context and we have one ref, it means that the
116 // ref will be lost and the object will be destroyed. Destroy the service
117 // explicitly here, so that cleanup can happen and client GL
118 // implementation does not print errors.
119 current_context->DestroyService();
120 } else {
121 current_context->decoder_->ReleaseSurface();
122 }
123 }
124
125 return true;
126 }
127
128 bool Context::ValidateAttributeList(const EGLint* attrib_list) {
129 if (attrib_list) {
130 for (int i = 0; attrib_list[i] != EGL_NONE; attrib_list += 2) {
131 switch (attrib_list[i]) {
132 case EGL_CONTEXT_CLIENT_VERSION:
133 break;
134 default:
135 return false;
136 }
137 }
138 }
139 return true;
140 }
141
142 gpu::Capabilities Context::GetCapabilities() {
143 return decoder_->GetCapabilities();
144 }
145
146 int32_t Context::CreateImage(ClientBuffer buffer,
147 size_t width,
148 size_t height,
149 unsigned internalformat) {
150 NOTIMPLEMENTED();
151 return -1;
152 }
153
154 void Context::DestroyImage(int32_t id) {
155 NOTIMPLEMENTED();
156 }
157
158 int32_t Context::CreateGpuMemoryBufferImage(size_t width,
159 size_t height,
160 unsigned internalformat,
161 unsigned usage) {
162 NOTIMPLEMENTED();
163 return -1;
164 }
165
166 void Context::SignalQuery(uint32_t query, const base::Closure& callback) {
167 NOTIMPLEMENTED();
168 }
169
170 void Context::SetLock(base::Lock*) {
171 NOTIMPLEMENTED();
172 }
173
174 bool Context::IsGpuChannelLost() {
175 NOTIMPLEMENTED();
176 return false;
177 }
178
179 void Context::EnsureWorkVisible() {
180 // This is only relevant for out-of-process command buffers.
181 }
182
183 gpu::CommandBufferNamespace Context::GetNamespaceID() const {
184 return gpu::CommandBufferNamespace::IN_PROCESS;
185 }
186
187 gpu::CommandBufferId Context::GetCommandBufferID() const {
188 return gpu::CommandBufferId();
189 }
190
191 int32_t Context::GetExtraCommandBufferData() const {
192 return 0;
193 }
194
195 uint64_t Context::GenerateFenceSyncRelease() {
196 return display_->GenerateFenceSyncRelease();
197 }
198
199 bool Context::IsFenceSyncRelease(uint64_t release) {
200 return display_->IsFenceSyncRelease(release);
201 }
202
203 bool Context::IsFenceSyncFlushed(uint64_t release) {
204 return display_->IsFenceSyncFlushed(release);
205 }
206
207 bool Context::IsFenceSyncFlushReceived(uint64_t release) {
208 return display_->IsFenceSyncFlushReceived(release);
209 }
210
211 void Context::SignalSyncToken(const gpu::SyncToken& sync_token,
212 const base::Closure& callback) {
213 NOTIMPLEMENTED();
214 }
215
216 bool Context::CanWaitUnverifiedSyncToken(const gpu::SyncToken* sync_token) {
217 return false;
218 }
219
220 void Context::ApplyCurrentContext(gfx::GLSurface* current_surface) {
221 DCHECK(HasService());
222 // The current_surface will be the same as
223 // the surface of the decoder. We can not DCHECK as there is
224 // no accessor.
225 if (!WasServiceContextLost()) {
226 if (!gl_context_->MakeCurrent(current_surface))
227 MarkServiceContextLost();
228 }
229 gles2::SetGLContext(client_gl_context_.get());
230 }
231
232 void Context::ApplyContextReleased() {
233 gles2::SetGLContext(nullptr);
234 }
235
236 bool Context::CreateService(gfx::GLSurface* gl_surface) {
237 scoped_refptr<gpu::TransferBufferManager> transfer_buffer_manager(
238 new gpu::TransferBufferManager(nullptr));
239 transfer_buffer_manager->Initialize();
240
241 scoped_ptr<gpu::CommandBufferService> command_buffer(
242 new gpu::CommandBufferService(transfer_buffer_manager.get()));
243 if (!command_buffer->Initialize())
244 return false;
245
246 scoped_refptr<gpu::gles2::ContextGroup> group(new gpu::gles2::ContextGroup(
247 NULL, NULL, new gpu::gles2::ShaderTranslatorCache,
248 new gpu::gles2::FramebufferCompletenessCache, NULL, NULL, NULL, true));
249
250 scoped_ptr<gpu::gles2::GLES2Decoder> decoder(
251 gpu::gles2::GLES2Decoder::Create(group.get()));
252 if (!decoder.get())
253 return false;
254
255 scoped_ptr<gpu::GpuScheduler> gpu_scheduler(new gpu::GpuScheduler(
256 command_buffer.get(), decoder.get(), decoder.get()));
257
258 decoder->set_engine(gpu_scheduler.get());
259
260 scoped_refptr<gfx::GLContext> gl_context(gfx::GLContext::CreateGLContext(
261 nullptr, gl_surface, gfx::PreferDiscreteGpu));
262 if (!gl_context)
263 return false;
264
265 gl_context->MakeCurrent(gl_surface);
266
267 gpu::gles2::ContextCreationAttribHelper helper;
268 config_->GetAttrib(EGL_ALPHA_SIZE, &helper.alpha_size);
269 config_->GetAttrib(EGL_BLUE_SIZE, &helper.blue_size);
270 config_->GetAttrib(EGL_GREEN_SIZE, &helper.green_size);
271 config_->GetAttrib(EGL_RED_SIZE, &helper.red_size);
272 config_->GetAttrib(EGL_DEPTH_SIZE, &helper.depth_size);
273 config_->GetAttrib(EGL_STENCIL_SIZE, &helper.stencil_size);
274 config_->GetAttrib(EGL_SAMPLES, &helper.samples);
275 config_->GetAttrib(EGL_SAMPLE_BUFFERS, &helper.sample_buffers);
276
277 helper.buffer_preserved = false;
278 helper.bind_generates_resource = kBindGeneratesResources;
279 helper.fail_if_major_perf_caveat = false;
280 helper.lose_context_when_out_of_memory = kLoseContextWhenOutOfMemory;
281 helper.context_type = gpu::gles2::CONTEXT_TYPE_OPENGLES2;
282 std::vector<int32_t> attribs;
283 helper.Serialize(&attribs);
284
285 if (!decoder->Initialize(gl_surface, gl_context.get(),
286 gl_surface->IsOffscreen(), gl_surface->GetSize(),
287 gpu::gles2::DisallowedFeatures(), attribs)) {
288 return false;
289 }
290
291 command_buffer->SetPutOffsetChangeCallback(base::Bind(
292 &gpu::GpuScheduler::PutChanged, base::Unretained(gpu_scheduler.get())));
293 command_buffer->SetGetBufferChangeCallback(base::Bind(
294 &gpu::GpuScheduler::SetGetBuffer, base::Unretained(gpu_scheduler.get())));
295
296 scoped_ptr<gpu::gles2::GLES2CmdHelper> gles2_cmd_helper(
297 new gpu::gles2::GLES2CmdHelper(command_buffer.get()));
298 if (!gles2_cmd_helper->Initialize(kCommandBufferSize)) {
299 decoder->Destroy(true);
300 return false;
301 }
302
303 scoped_ptr<gpu::TransferBuffer> transfer_buffer(
304 new gpu::TransferBuffer(gles2_cmd_helper.get()));
305
306 gles2_cmd_helper_.reset(gles2_cmd_helper.release());
307 transfer_buffer_.reset(transfer_buffer.release());
308 command_buffer_.reset(command_buffer.release());
309 gpu_scheduler_.reset(gpu_scheduler.release());
310 decoder_.reset(decoder.release());
311 gl_context_ = gl_context.get();
312
313 scoped_ptr<gpu::gles2::GLES2Implementation> context(
314 new gpu::gles2::GLES2Implementation(
315 gles2_cmd_helper_.get(), nullptr, transfer_buffer_.get(),
316 kBindGeneratesResources, kLoseContextWhenOutOfMemory,
317 kSupportClientSideArrays, this));
318
319 if (!context->Initialize(kTransferBufferSize, kTransferBufferSize / 2,
320 kTransferBufferSize * 2,
321 gpu::gles2::GLES2Implementation::kNoLimit)) {
322 DestroyService();
323 return false;
324 }
325
326 context->EnableFeatureCHROMIUM("pepper3d_allow_buffers_on_multiple_targets");
327 context->EnableFeatureCHROMIUM("pepper3d_support_fixed_attribs");
328 client_gl_context_.reset(context.release());
329 return true;
330 }
331
332 void Context::DestroyService() {
333 DCHECK(HasService());
334 bool have_context = !WasServiceContextLost();
335 // The client gl interface might still be set to current global
336 // interface. This will be cleaned up in ApplyContextReleased
337 // with AutoCurrentContextRestore.
338 client_gl_context_.reset();
339 gl_context_ = nullptr;
340
341 transfer_buffer_.reset();
342 gpu_scheduler_.reset();
343 if (decoder_)
344 decoder_->Destroy(have_context);
345 gles2_cmd_helper_.reset();
346 command_buffer_.reset();
347 }
348
349 bool Context::HasService() const {
350 return decoder_ != nullptr;
351 }
352
353 void Context::MarkServiceContextLost() {
354 decoder_->MarkContextLost(gpu::error::kMakeCurrentFailed);
355 }
356
357 bool Context::WasServiceContextLost() const {
358 return decoder_->WasContextLost();
359 }
360
361 bool Context::IsCompatibleSurface(gfx::GLSurface* gl_surface) {
362 EGLint value = EGL_NONE;
363 config_->GetAttrib(EGL_SURFACE_TYPE, &value);
364 bool config_is_offscreen = (value & EGL_PBUFFER_BIT) != 0;
365 return gl_surface->IsOffscreen() == config_is_offscreen;
366 }
367
368 bool Context::Flush(gfx::GLSurface* gl_surface) {
369 if (WasServiceContextLost())
370 return false;
371 if (!gl_context_->MakeCurrent(gl_surface)) {
372 MarkServiceContextLost();
373 return false;
374 }
375 client_gl_context_->Flush();
376 return true;
377 }
378
379 } // namespace egl
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698