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

Side by Side Diff: content/renderer/renderer_gl_context.cc

Issue 7066035: Moved GPU related files in content/renderer into gpu subdirectory. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 7 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 | Annotate | Revision Log
« no previous file with comments | « content/renderer/renderer_gl_context.h ('k') | content/renderer/renderer_webkitclient_impl.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 "content/renderer/renderer_gl_context.h"
6
7 #include "base/debug/trace_event.h"
8 #include "base/lazy_instance.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/memory/singleton.h"
12 #include "base/memory/weak_ptr.h"
13 #include "base/shared_memory.h"
14 #include "content/common/view_messages.h"
15 #include "content/renderer/command_buffer_proxy.h"
16 #include "content/renderer/gpu_channel_host.h"
17 #include "content/renderer/gpu_video_service_host.h"
18 #include "content/renderer/media/gles2_video_decode_context.h"
19 #include "content/renderer/render_thread.h"
20 #include "content/renderer/render_widget.h"
21 #include "content/renderer/transport_texture_host.h"
22 #include "content/renderer/transport_texture_service.h"
23 #include "googleurl/src/gurl.h"
24 #include "ipc/ipc_channel_handle.h"
25
26 #if defined(ENABLE_GPU)
27 #include "gpu/command_buffer/client/gles2_cmd_helper.h"
28 #include "gpu/command_buffer/client/gles2_implementation.h"
29 #include "gpu/command_buffer/client/gles2_lib.h"
30 #include "gpu/command_buffer/common/constants.h"
31 #include "gpu/GLES2/gles2_command_buffer.h"
32 #endif // ENABLE_GPU
33
34 namespace {
35
36 const int32 kCommandBufferSize = 1024 * 1024;
37 // TODO(kbr): make the transfer buffer size configurable via context
38 // creation attributes.
39 const int32 kTransferBufferSize = 1024 * 1024;
40
41 const uint32 kMaxLatchesPerRenderer = 2048;
42 const uint32 kInvalidLatchId = 0xffffffffu;
43
44 // Singleton used to initialize and terminate the gles2 library.
45 class GLES2Initializer {
46 public:
47 GLES2Initializer() {
48 gles2::Initialize();
49 }
50
51 ~GLES2Initializer() {
52 gles2::Terminate();
53 }
54
55 private:
56 DISALLOW_COPY_AND_ASSIGN(GLES2Initializer);
57 };
58
59 // Shared memory allocator for latches. Creates a block of shared memory for
60 // each renderer process.
61 class LatchAllocator {
62 public:
63 static LatchAllocator* GetInstance();
64 static uint32 size() { return kMaxLatchesPerRenderer*sizeof(uint32); }
65 static const uint32_t kFreeLatch = 0xffffffffu;
66
67 LatchAllocator();
68 ~LatchAllocator();
69
70 base::SharedMemoryHandle handle() const { return shm_->handle(); }
71 base::SharedMemory* shared_memory() { return shm_.get(); }
72
73 bool AllocateLatch(uint32* latch_id);
74 bool FreeLatch(uint32 latch_id);
75
76 private:
77 friend struct DefaultSingletonTraits<LatchAllocator>;
78
79 scoped_ptr<base::SharedMemory> shm_;
80 // Pointer to mapped shared memory.
81 volatile uint32* latches_;
82
83 DISALLOW_COPY_AND_ASSIGN(LatchAllocator);
84 };
85
86 ////////////////////////////////////////////////////////////////////////////////
87 /// LatchAllocator implementation
88
89 LatchAllocator* LatchAllocator::GetInstance() {
90 return Singleton<LatchAllocator>::get();
91 }
92
93 LatchAllocator::LatchAllocator() {
94 base::SharedMemoryHandle handle;
95 RenderThread* render_thread = RenderThread::current();
96 if (!render_thread->Send(
97 new ViewHostMsg_AllocateSharedMemoryBuffer(size(), &handle))) {
98 NOTREACHED() << "failed to send sync IPC";
99 }
100
101 if (!base::SharedMemory::IsHandleValid(handle)) {
102 NOTREACHED() << "failed to create shared memory";
103 }
104
105 // Handle is closed by the SharedMemory object below. This stops
106 // base::FileDescriptor from closing it as well.
107 #if defined(OS_POSIX)
108 handle.auto_close = false;
109 #endif
110
111 shm_.reset(new base::SharedMemory(handle, false));
112 if (!shm_->Map(size())) {
113 NOTREACHED() << "failed to map shared memory";
114 }
115
116 latches_ = static_cast<uint32*>(shm_->memory());
117 // Mark all latches as unallocated.
118 for (uint32 i = 0; i < kMaxLatchesPerRenderer; ++i)
119 latches_[i] = kFreeLatch;
120 }
121
122 LatchAllocator::~LatchAllocator() {
123 }
124
125 bool LatchAllocator::AllocateLatch(uint32* latch_id) {
126 for (uint32 i = 0; i < kMaxLatchesPerRenderer; ++i) {
127 if (latches_[i] == kFreeLatch) {
128 // mark latch as taken and blocked.
129 // 0 means waiter will block, 1 means waiter will pass.
130 latches_[i] = 0;
131 *latch_id = i;
132 return true;
133 }
134 }
135 return false;
136 }
137
138 bool LatchAllocator::FreeLatch(uint32 latch_id) {
139 if (latch_id < kMaxLatchesPerRenderer && latches_[latch_id] != kFreeLatch) {
140 latches_[latch_id] = kFreeLatch;
141 return true;
142 }
143 return false;
144 }
145
146 ////////////////////////////////////////////////////////////////////////////////
147
148 static base::LazyInstance<GLES2Initializer> g_gles2_initializer(
149 base::LINKER_INITIALIZED);
150
151 } // namespace anonymous
152
153 RendererGLContext::~RendererGLContext() {
154 Destroy();
155 }
156
157 RendererGLContext* RendererGLContext::CreateViewContext(
158 GpuChannelHost* channel,
159 gfx::PluginWindowHandle render_surface,
160 int render_view_id,
161 const char* allowed_extensions,
162 const int32* attrib_list,
163 const GURL& active_url) {
164 #if defined(ENABLE_GPU)
165 scoped_ptr<RendererGLContext> context(new RendererGLContext(channel, NULL));
166 if (!context->Initialize(
167 true,
168 render_surface,
169 render_view_id,
170 gfx::Size(),
171 allowed_extensions,
172 attrib_list,
173 active_url))
174 return NULL;
175
176 return context.release();
177 #else
178 return NULL;
179 #endif
180 }
181
182 #if defined(OS_MACOSX)
183 void RendererGLContext::ResizeOnscreen(const gfx::Size& size) {
184 DCHECK(size.width() > 0 && size.height() > 0);
185 size_ = size;
186 command_buffer_->SetWindowSize(size);
187 }
188 #endif
189
190 RendererGLContext* RendererGLContext::CreateOffscreenContext(
191 GpuChannelHost* channel,
192 RendererGLContext* parent,
193 const gfx::Size& size,
194 const char* allowed_extensions,
195 const int32* attrib_list,
196 const GURL& active_url) {
197 #if defined(ENABLE_GPU)
198 scoped_ptr<RendererGLContext> context(new RendererGLContext(channel, parent));
199 if (!context->Initialize(
200 false,
201 gfx::kNullPluginWindow,
202 0,
203 size,
204 allowed_extensions,
205 attrib_list,
206 active_url))
207 return NULL;
208
209 return context.release();
210 #else
211 return NULL;
212 #endif
213 }
214
215 void RendererGLContext::ResizeOffscreen(const gfx::Size& size) {
216 DCHECK(size.width() > 0 && size.height() > 0);
217 if (size_ != size) {
218 command_buffer_->ResizeOffscreenFrameBuffer(size);
219 size_ = size;
220 }
221 }
222
223 uint32 RendererGLContext::GetParentTextureId() {
224 return parent_texture_id_;
225 }
226
227 uint32 RendererGLContext::CreateParentTexture(const gfx::Size& size) {
228 // Allocate a texture ID with respect to the parent.
229 if (parent_.get()) {
230 if (!MakeCurrent(parent_.get()))
231 return 0;
232 uint32 texture_id = parent_->gles2_implementation_->MakeTextureId();
233 parent_->gles2_implementation_->BindTexture(GL_TEXTURE_2D, texture_id);
234 parent_->gles2_implementation_->TexParameteri(
235 GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
236 parent_->gles2_implementation_->TexParameteri(
237 GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
238 parent_->gles2_implementation_->TexParameteri(
239 GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
240 parent_->gles2_implementation_->TexParameteri(
241 GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
242
243 parent_->gles2_implementation_->TexImage2D(GL_TEXTURE_2D,
244 0, // mip level
245 GL_RGBA,
246 size.width(),
247 size.height(),
248 0, // border
249 GL_RGBA,
250 GL_UNSIGNED_BYTE,
251 NULL);
252 // Make sure that the parent texture's storage is allocated before we let
253 // the caller attempt to use it.
254 int32 token = parent_->gles2_helper_->InsertToken();
255 parent_->gles2_helper_->WaitForToken(token);
256 return texture_id;
257 }
258 return 0;
259 }
260
261 void RendererGLContext::DeleteParentTexture(uint32 texture) {
262 if (parent_.get()) {
263 if (!MakeCurrent(parent_.get()))
264 return;
265 parent_->gles2_implementation_->DeleteTextures(1, &texture);
266 }
267 }
268
269 void RendererGLContext::SetSwapBuffersCallback(Callback0::Type* callback) {
270 swap_buffers_callback_.reset(callback);
271 }
272
273 void RendererGLContext::SetContextLostCallback(Callback0::Type* callback) {
274 context_lost_callback_.reset(callback);
275 }
276
277 bool RendererGLContext::MakeCurrent(RendererGLContext* context) {
278 if (context) {
279 gles2::SetGLContext(context->gles2_implementation_);
280
281 // Don't request latest error status from service. Just use the locally
282 // cached information from the last flush.
283 // TODO(apatrick): I'm not sure if this should actually change the
284 // current context if it fails. For now it gets changed even if it fails
285 // because making GL calls with a NULL context crashes.
286 if (context->command_buffer_->GetLastState().error != gpu::error::kNoError)
287 return false;
288 } else {
289 gles2::SetGLContext(NULL);
290 }
291
292 return true;
293 }
294
295 bool RendererGLContext::SwapBuffers() {
296 TRACE_EVENT1("gpu", "RendererGLContext::SwapBuffers", "frame", frame_number_);
297 frame_number_++;
298
299 // Don't request latest error status from service. Just use the locally cached
300 // information from the last flush.
301 if (command_buffer_->GetLastState().error != gpu::error::kNoError)
302 return false;
303
304 gles2_implementation_->SwapBuffers();
305 return true;
306 }
307
308 media::VideoDecodeEngine* RendererGLContext::CreateVideoDecodeEngine() {
309 return channel_->gpu_video_service_host()->CreateVideoDecoder(
310 command_buffer_->route_id());
311 }
312
313 media::VideoDecodeContext* RendererGLContext::CreateVideoDecodeContext(
314 MessageLoop* message_loop, bool hardware_decoder) {
315 return new Gles2VideoDecodeContext(message_loop, hardware_decoder, this);
316 }
317
318 scoped_refptr<TransportTextureHost>
319 RendererGLContext::CreateTransportTextureHost() {
320 return channel_->transport_texture_service()->CreateTransportTextureHost(
321 this, command_buffer_->route_id());
322 }
323
324 RendererGLContext::Error RendererGLContext::GetError() {
325 gpu::CommandBuffer::State state = command_buffer_->GetState();
326 if (state.error == gpu::error::kNoError) {
327 Error old_error = last_error_;
328 last_error_ = SUCCESS;
329 return old_error;
330 } else {
331 // All command buffer errors are unrecoverable. The error is treated as a
332 // lost context: destroy the context and create another one.
333 return CONTEXT_LOST;
334 }
335 }
336
337 bool RendererGLContext::IsCommandBufferContextLost() {
338 gpu::CommandBuffer::State state = command_buffer_->GetLastState();
339 return state.error == gpu::error::kLostContext;
340 }
341
342 CommandBufferProxy* RendererGLContext::GetCommandBufferProxy() {
343 return command_buffer_;
344 }
345
346 // TODO(gman): Remove This
347 void RendererGLContext::DisableShaderTranslation() {
348 gles2_implementation_->CommandBufferEnableCHROMIUM(
349 PEPPER3D_SKIP_GLSL_TRANSLATION);
350 }
351
352 gpu::gles2::GLES2Implementation* RendererGLContext::GetImplementation() {
353 return gles2_implementation_;
354 }
355
356 RendererGLContext::RendererGLContext(GpuChannelHost* channel,
357 RendererGLContext* parent)
358 : channel_(channel),
359 parent_(parent ?
360 parent->AsWeakPtr() : base::WeakPtr<RendererGLContext>()),
361 parent_texture_id_(0),
362 child_to_parent_latch_(kInvalidLatchId),
363 parent_to_child_latch_(kInvalidLatchId),
364 latch_transfer_buffer_id_(-1),
365 command_buffer_(NULL),
366 gles2_helper_(NULL),
367 transfer_buffer_id_(-1),
368 gles2_implementation_(NULL),
369 last_error_(SUCCESS),
370 frame_number_(0) {
371 DCHECK(channel);
372 }
373
374 bool RendererGLContext::Initialize(bool onscreen,
375 gfx::PluginWindowHandle render_surface,
376 int render_view_id,
377 const gfx::Size& size,
378 const char* allowed_extensions,
379 const int32* attrib_list,
380 const GURL& active_url) {
381 DCHECK(size.width() >= 0 && size.height() >= 0);
382 TRACE_EVENT2("gpu", "RendererGLContext::Initialize",
383 "on_screen", onscreen, "num_pixels", size.GetArea());
384
385 if (channel_->state() != GpuChannelHost::kConnected)
386 return false;
387
388 // Ensure the gles2 library is initialized first in a thread safe way.
389 g_gles2_initializer.Get();
390
391 // Allocate a frame buffer ID with respect to the parent.
392 if (parent_.get()) {
393 // Flush any remaining commands in the parent context to make sure the
394 // texture id accounting stays consistent.
395 int32 token = parent_->gles2_helper_->InsertToken();
396 parent_->gles2_helper_->WaitForToken(token);
397 parent_texture_id_ = parent_->gles2_implementation_->MakeTextureId();
398 }
399
400 std::vector<int32> attribs;
401 while (attrib_list) {
402 int32 attrib = *attrib_list++;
403 switch (attrib) {
404 // Known attributes
405 case ALPHA_SIZE:
406 case BLUE_SIZE:
407 case GREEN_SIZE:
408 case RED_SIZE:
409 case DEPTH_SIZE:
410 case STENCIL_SIZE:
411 case SAMPLES:
412 case SAMPLE_BUFFERS:
413 attribs.push_back(attrib);
414 attribs.push_back(*attrib_list++);
415 break;
416 case NONE:
417 attribs.push_back(attrib);
418 attrib_list = NULL;
419 break;
420 default:
421 last_error_ = BAD_ATTRIBUTE;
422 attribs.push_back(NONE);
423 attrib_list = NULL;
424 break;
425 }
426 }
427
428 // Create a proxy to a command buffer in the GPU process.
429 if (onscreen) {
430 if (render_surface == gfx::kNullPluginWindow) {
431 LOG(ERROR) << "Invalid surface handle for onscreen context.";
432 command_buffer_ = NULL;
433 } else {
434 command_buffer_ = channel_->CreateViewCommandBuffer(
435 render_surface,
436 render_view_id,
437 allowed_extensions,
438 attribs,
439 active_url);
440 }
441 } else {
442 CommandBufferProxy* parent_command_buffer =
443 parent_.get() ? parent_->command_buffer_ : NULL;
444 command_buffer_ = channel_->CreateOffscreenCommandBuffer(
445 parent_command_buffer,
446 size,
447 allowed_extensions,
448 attribs,
449 parent_texture_id_,
450 active_url);
451 }
452 if (!command_buffer_) {
453 Destroy();
454 return false;
455 }
456
457 // Initiaize the command buffer.
458 if (!command_buffer_->Initialize(kCommandBufferSize)) {
459 Destroy();
460 return false;
461 }
462
463 command_buffer_->SetSwapBuffersCallback(
464 NewCallback(this, &RendererGLContext::OnSwapBuffers));
465
466 command_buffer_->SetChannelErrorCallback(
467 NewCallback(this, &RendererGLContext::OnContextLost));
468
469 // Create the GLES2 helper, which writes the command buffer protocol.
470 gles2_helper_ = new gpu::gles2::GLES2CmdHelper(command_buffer_);
471 if (!gles2_helper_->Initialize(kCommandBufferSize)) {
472 Destroy();
473 return false;
474 }
475
476 // Create a transfer buffer used to copy resources between the renderer
477 // process and the GPU process.
478 transfer_buffer_id_ =
479 command_buffer_->CreateTransferBuffer(kTransferBufferSize,
480 gpu::kCommandBufferSharedMemoryId);
481 if (transfer_buffer_id_ < 0) {
482 Destroy();
483 return false;
484 }
485
486 // Map the buffer into the renderer process's address space.
487 gpu::Buffer transfer_buffer =
488 command_buffer_->GetTransferBuffer(transfer_buffer_id_);
489 if (!transfer_buffer.ptr) {
490 Destroy();
491 return false;
492 }
493
494 // Register transfer buffer so that the context can access latches.
495 LatchAllocator* latch_shm = LatchAllocator::GetInstance();
496 latch_transfer_buffer_id_ = command_buffer_->RegisterTransferBuffer(
497 latch_shm->shared_memory(), LatchAllocator::size(),
498 gpu::kLatchSharedMemoryId);
499 if (latch_transfer_buffer_id_ != gpu::kLatchSharedMemoryId) {
500 Destroy();
501 return false;
502 }
503
504 // If this is a child context, setup latches for synchronization between child
505 // and parent.
506 if (parent_.get()) {
507 if (!CreateLatch(&child_to_parent_latch_) ||
508 !CreateLatch(&parent_to_child_latch_)) {
509 Destroy();
510 return false;
511 }
512 }
513
514 // Create the object exposing the OpenGL API.
515 gles2_implementation_ = new gpu::gles2::GLES2Implementation(
516 gles2_helper_,
517 transfer_buffer.size,
518 transfer_buffer.ptr,
519 transfer_buffer_id_,
520 false);
521
522 size_ = size;
523
524 return true;
525 }
526
527 void RendererGLContext::Destroy() {
528 if (parent_.get() && parent_texture_id_ != 0) {
529 parent_->gles2_implementation_->FreeTextureId(parent_texture_id_);
530 parent_texture_id_ = 0;
531 }
532
533 delete gles2_implementation_;
534 gles2_implementation_ = NULL;
535
536 if (child_to_parent_latch_ != kInvalidLatchId) {
537 DestroyLatch(child_to_parent_latch_);
538 child_to_parent_latch_ = kInvalidLatchId;
539 }
540 if (parent_to_child_latch_ != kInvalidLatchId) {
541 DestroyLatch(parent_to_child_latch_);
542 parent_to_child_latch_ = kInvalidLatchId;
543 }
544 if (command_buffer_ && latch_transfer_buffer_id_ != -1) {
545 command_buffer_->DestroyTransferBuffer(latch_transfer_buffer_id_);
546 latch_transfer_buffer_id_ = -1;
547 }
548
549 if (command_buffer_ && transfer_buffer_id_ != -1) {
550 command_buffer_->DestroyTransferBuffer(transfer_buffer_id_);
551 transfer_buffer_id_ = -1;
552 }
553
554 delete gles2_helper_;
555 gles2_helper_ = NULL;
556
557 if (channel_ && command_buffer_) {
558 channel_->DestroyCommandBuffer(command_buffer_);
559 command_buffer_ = NULL;
560 }
561
562 channel_ = NULL;
563 }
564
565 void RendererGLContext::OnSwapBuffers() {
566 if (swap_buffers_callback_.get())
567 swap_buffers_callback_->Run();
568 }
569
570 void RendererGLContext::OnContextLost() {
571 if (context_lost_callback_.get())
572 context_lost_callback_->Run();
573 }
574
575 bool RendererGLContext::CreateLatch(uint32* ret_latch) {
576 return LatchAllocator::GetInstance()->AllocateLatch(ret_latch);
577 }
578
579 bool RendererGLContext::DestroyLatch(uint32 latch) {
580 return LatchAllocator::GetInstance()->FreeLatch(latch);
581 }
582
583 bool RendererGLContext::GetParentToChildLatch(uint32* parent_to_child_latch) {
584 if (parent_.get()) {
585 *parent_to_child_latch = parent_to_child_latch_;
586 return true;
587 }
588 return false;
589 }
590
591 bool RendererGLContext::GetChildToParentLatch(uint32* child_to_parent_latch) {
592 if (parent_.get()) {
593 *child_to_parent_latch = child_to_parent_latch_;
594 return true;
595 }
596 return false;
597 }
OLDNEW
« no previous file with comments | « content/renderer/renderer_gl_context.h ('k') | content/renderer/renderer_webkitclient_impl.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698