1 // Copyright 2013 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 "mojo/services/gles2/command_buffer_impl.h" 6 7 #include "base/bind.h" 8 #include "base/memory/shared_memory.h" 9 10 #include "gpu/command_buffer/common/constants.h" 11 #include "gpu/command_buffer/service/command_buffer_service.h" 12 #include "gpu/command_buffer/service/context_group.h" 13 #include "gpu/command_buffer/service/gles2_cmd_decoder.h" 14 #include "gpu/command_buffer/service/gpu_control_service.h" 15 #include "gpu/command_buffer/service/gpu_scheduler.h" 16 #include "gpu/command_buffer/service/image_manager.h" 17 #include "gpu/command_buffer/service/mailbox_manager.h" 18 #include "gpu/command_buffer/service/memory_tracking.h" 19 #include "mojo/services/gles2/command_buffer_type_conversions.h" 20 #include "mojo/services/gles2/mojo_buffer_backing.h" 21 #include "ui/gl/gl_context.h" 22 #include "ui/gl/gl_surface.h" 23 24 namespace mojo { 25 namespace services { 26 27 namespace { 28 29 class MemoryTrackerStub : public gpu::gles2::MemoryTracker { 30 public: 31 MemoryTrackerStub() {} 32 33 virtual void TrackMemoryAllocatedChange(size_t old_size, 34 size_t new_size, 35 gpu::gles2::MemoryTracker::Pool pool) 36 OVERRIDE {} 37 38 virtual bool EnsureGPUMemoryAvailable(size_t size_needed) OVERRIDE { 39 return true; 40 }; 41 42 private: 43 virtual ~MemoryTrackerStub() {} 44 45 DISALLOW_COPY_AND_ASSIGN(MemoryTrackerStub); 46 }; 47 48 } // anonymous namespace 49 50 CommandBufferImpl::CommandBufferImpl(gfx::AcceleratedWidget widget, 51 const gfx::Size& size) 52 : widget_(widget), size_(size) {} 53 54 CommandBufferImpl::~CommandBufferImpl() { 55 client()->DidDestroy(); 56 if (decoder_.get()) { 57 bool have_context = decoder_->MakeCurrent(); 58 decoder_->Destroy(have_context); 59 } 60 } 61 62 void CommandBufferImpl::OnConnectionError() { 63 // TODO(darin): How should we handle this error? 64 } 65 66 void CommandBufferImpl::Initialize( 67 CommandBufferSyncClientPtr sync_client, 68 mojo::ScopedSharedBufferHandle shared_state) { 69 sync_client_ = sync_client.Pass(); 70 sync_client_->DidInitialize(DoInitialize(shared_state.Pass())); 71 } 72 73 bool CommandBufferImpl::DoInitialize( 74 mojo::ScopedSharedBufferHandle shared_state) { 75 // TODO(piman): offscreen surface. 76 scoped_refptr<gfx::GLSurface> surface = 77 gfx::GLSurface::CreateViewGLSurface(widget_); 78 if (!surface.get()) 79 return false; 80 81 // TODO(piman): context sharing, virtual contexts, gpu preference. 82 scoped_refptr<gfx::GLContext> context = gfx::GLContext::CreateGLContext( 83 NULL, surface.get(), gfx::PreferIntegratedGpu); 84 if (!context.get()) 85 return false; 86 87 if (!context->MakeCurrent(surface.get())) 88 return false; 89 90 // TODO(piman): ShaderTranslatorCache is currently per-ContextGroup but 91 // only needs to be per-thread. 92 scoped_refptr<gpu::gles2::ContextGroup> context_group = 93 new gpu::gles2::ContextGroup(NULL, 94 NULL, 95 new MemoryTrackerStub, 96 new gpu::gles2::ShaderTranslatorCache, 97 NULL, 98 true); 99 100 command_buffer_.reset( 101 new gpu::CommandBufferService(context_group->transfer_buffer_manager())); 102 bool result = command_buffer_->Initialize(); 103 DCHECK(result); 104 105 decoder_.reset(::gpu::gles2::GLES2Decoder::Create(context_group.get())); 106 scheduler_.reset(new gpu::GpuScheduler( 107 command_buffer_.get(), decoder_.get(), decoder_.get())); 108 decoder_->set_engine(scheduler_.get()); 109 110 gpu::gles2::DisallowedFeatures disallowed_features; 111 112 // TODO(piman): attributes. 113 std::vector<int32> attrib_vector; 114 if (!decoder_->Initialize(surface, 115 context, 116 false /* offscreen */, 117 size_, 118 disallowed_features, 119 attrib_vector)) 120 return false; 121 122 gpu_control_.reset( 123 new gpu::GpuControlService(context_group->image_manager(), NULL)); 124 125 command_buffer_->SetPutOffsetChangeCallback(base::Bind( 126 &gpu::GpuScheduler::PutChanged, base::Unretained(scheduler_.get()))); 127 command_buffer_->SetGetBufferChangeCallback(base::Bind( 128 &gpu::GpuScheduler::SetGetBuffer, base::Unretained(scheduler_.get()))); 129 command_buffer_->SetParseErrorCallback( 130 base::Bind(&CommandBufferImpl::OnParseError, base::Unretained(this))); 131 132 // TODO(piman): other callbacks 133 134 const size_t kSize = sizeof(gpu::CommandBufferSharedState); 135 scoped_ptr<gpu::BufferBacking> backing( 136 gles2::MojoBufferBacking::Create(shared_state.Pass(), kSize)); 137 if (!backing.get()) 138 return false; 139 140 command_buffer_->SetSharedStateBuffer(backing.Pass()); 141 return true; 142 } 143 144 void CommandBufferImpl::SetGetBuffer(int32_t buffer) { 145 command_buffer_->SetGetBuffer(buffer); 146 } 147 148 void CommandBufferImpl::Flush(int32_t put_offset) { 149 command_buffer_->Flush(put_offset); 150 } 151 152 void CommandBufferImpl::MakeProgress(int32_t last_get_offset) { 153 // TODO(piman): handle out-of-order. 154 sync_client_->DidMakeProgress( 155 CommandBufferState::From(command_buffer_->GetLastState())); 156 } 157 158 void CommandBufferImpl::RegisterTransferBuffer( 159 int32_t id, 160 mojo::ScopedSharedBufferHandle transfer_buffer, 161 uint32_t size) { 162 // Take ownership of the memory and map it into this process. 163 // This validates the size. 164 scoped_ptr<gpu::BufferBacking> backing( 165 gles2::MojoBufferBacking::Create(transfer_buffer.Pass(), size)); 166 if (!backing.get()) { 167 DVLOG(0) << "Failed to map shared memory."; 168 return; 169 } 170 command_buffer_->RegisterTransferBuffer(id, backing.Pass()); 171 } 172 173 void CommandBufferImpl::DestroyTransferBuffer(int32_t id) { 174 command_buffer_->DestroyTransferBuffer(id); 175 } 176 177 void CommandBufferImpl::Echo(const Callback<void()>& callback) { 178 callback.Run(); 179 } 180 181 void CommandBufferImpl::RequestAnimationFrames() { 182 timer_.Start(FROM_HERE, 183 base::TimeDelta::FromMilliseconds(16), 184 this, 185 &CommandBufferImpl::DrawAnimationFrame); 186 } 187 188 void CommandBufferImpl::CancelAnimationFrames() { timer_.Stop(); } 189 190 void CommandBufferImpl::OnParseError() { 191 gpu::CommandBuffer::State state = command_buffer_->GetLastState(); 192 client()->LostContext(state.context_lost_reason); 193 } 194 195 void CommandBufferImpl::DrawAnimationFrame() { client()->DrawAnimationFrame(); } 196 197 } // namespace services 198 } // namespace mojo 199