1 // Copyright 2014 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.
5 #include "mojo/gles2/command_buffer_client_impl.h"
9 #include "base/logging.h"
10 #include "base/process/process_handle.h"
11 #include "components/view_manager/gles2/command_buffer_type_conversions.h"
12 #include "components/view_manager/gles2/mojo_buffer_backing.h"
13 #include "components/view_manager/gles2/mojo_gpu_memory_buffer.h"
14 #include "gpu/command_buffer/service/image_factory.h"
15 #include "mojo/platform_handle/platform_handle_functions.h"
21 bool CreateMapAndDupSharedBuffer(size_t size
,
23 mojo::ScopedSharedBufferHandle
* handle
,
24 mojo::ScopedSharedBufferHandle
* duped
) {
25 MojoResult result
= mojo::CreateSharedBuffer(NULL
, size
, handle
);
26 if (result
!= MOJO_RESULT_OK
)
28 DCHECK(handle
->is_valid());
30 result
= mojo::DuplicateBuffer(handle
->get(), NULL
, duped
);
31 if (result
!= MOJO_RESULT_OK
)
33 DCHECK(duped
->is_valid());
35 result
= mojo::MapBuffer(
36 handle
->get(), 0, size
, memory
, MOJO_MAP_BUFFER_FLAG_NONE
);
37 if (result
!= MOJO_RESULT_OK
)
46 CommandBufferDelegate::~CommandBufferDelegate() {}
48 void CommandBufferDelegate::ContextLost() {}
50 class CommandBufferClientImpl::SyncClientImpl
51 : public mojo::CommandBufferSyncClient
{
53 SyncClientImpl(mojo::CommandBufferSyncClientPtr
* ptr
,
54 const MojoAsyncWaiter
* async_waiter
)
55 : initialized_successfully_(false), binding_(this, ptr
, async_waiter
) {}
57 bool WaitForInitialization() {
58 if (!binding_
.WaitForIncomingMethodCall())
60 return initialized_successfully_
;
63 mojo::CommandBufferStatePtr
WaitForProgress() {
64 if (!binding_
.WaitForIncomingMethodCall())
65 return mojo::CommandBufferStatePtr();
66 return command_buffer_state_
.Pass();
69 gpu::Capabilities
GetCapabilities() {
71 return capabilities_
.To
<gpu::Capabilities
>();
72 return gpu::Capabilities();
76 // CommandBufferSyncClient methods:
77 void DidInitialize(bool success
,
78 mojo::GpuCapabilitiesPtr capabilities
) override
{
79 initialized_successfully_
= success
;
80 capabilities_
= capabilities
.Pass();
82 void DidMakeProgress(mojo::CommandBufferStatePtr state
) override
{
83 command_buffer_state_
= state
.Pass();
86 bool initialized_successfully_
;
87 mojo::GpuCapabilitiesPtr capabilities_
;
88 mojo::CommandBufferStatePtr command_buffer_state_
;
89 mojo::Binding
<mojo::CommandBufferSyncClient
> binding_
;
91 DISALLOW_COPY_AND_ASSIGN(SyncClientImpl
);
94 class CommandBufferClientImpl::SyncPointClientImpl
95 : public mojo::CommandBufferSyncPointClient
{
97 SyncPointClientImpl(mojo::CommandBufferSyncPointClientPtr
* ptr
,
98 const MojoAsyncWaiter
* async_waiter
)
99 : sync_point_(0u), binding_(this, ptr
, async_waiter
) {}
101 uint32_t WaitForInsertSyncPoint() {
102 if (!binding_
.WaitForIncomingMethodCall())
104 uint32_t result
= sync_point_
;
110 void DidInsertSyncPoint(uint32_t sync_point
) override
{
111 sync_point_
= sync_point
;
114 uint32_t sync_point_
;
116 mojo::Binding
<mojo::CommandBufferSyncPointClient
> binding_
;
119 CommandBufferClientImpl::CommandBufferClientImpl(
120 CommandBufferDelegate
* delegate
,
121 const MojoAsyncWaiter
* async_waiter
,
122 mojo::ScopedMessagePipeHandle command_buffer_handle
)
123 : delegate_(delegate
),
124 observer_binding_(this),
126 last_put_offset_(-1),
127 next_transfer_buffer_id_(0),
129 async_waiter_(async_waiter
) {
130 command_buffer_
.Bind(mojo::InterfacePtrInfo
<mojo::CommandBuffer
>(
131 command_buffer_handle
.Pass(), 0u),
133 command_buffer_
.set_connection_error_handler(
134 [this]() { DidLoseContext(gpu::error::kUnknown
); });
137 CommandBufferClientImpl::~CommandBufferClientImpl() {}
139 bool CommandBufferClientImpl::Initialize() {
140 const size_t kSharedStateSize
= sizeof(gpu::CommandBufferSharedState
);
142 mojo::ScopedSharedBufferHandle duped
;
143 bool result
= CreateMapAndDupSharedBuffer(
144 kSharedStateSize
, &memory
, &shared_state_handle_
, &duped
);
148 shared_state_
= static_cast<gpu::CommandBufferSharedState
*>(memory
);
150 shared_state()->Initialize();
152 mojo::CommandBufferSyncClientPtr sync_client
;
153 sync_client_impl_
.reset(new SyncClientImpl(&sync_client
, async_waiter_
));
155 mojo::CommandBufferSyncPointClientPtr sync_point_client
;
156 sync_point_client_impl_
.reset(
157 new SyncPointClientImpl(&sync_point_client
, async_waiter_
));
159 mojo::CommandBufferLostContextObserverPtr observer_ptr
;
160 observer_binding_
.Bind(GetProxy(&observer_ptr
), async_waiter_
);
161 command_buffer_
->Initialize(sync_client
.Pass(),
162 sync_point_client
.Pass(),
166 // Wait for DidInitialize to come on the sync client pipe.
167 if (!sync_client_impl_
->WaitForInitialization()) {
168 VLOG(1) << "Channel encountered error while creating command buffer";
171 capabilities_
= sync_client_impl_
->GetCapabilities();
175 gpu::CommandBuffer::State
CommandBufferClientImpl::GetLastState() {
179 int32
CommandBufferClientImpl::GetLastToken() {
181 return last_state_
.token
;
184 void CommandBufferClientImpl::Flush(int32 put_offset
) {
185 if (last_put_offset_
== put_offset
)
188 last_put_offset_
= put_offset
;
189 command_buffer_
->Flush(put_offset
);
192 void CommandBufferClientImpl::OrderingBarrier(int32_t put_offset
) {
193 // TODO(jamesr): Implement this more efficiently.
197 void CommandBufferClientImpl::WaitForTokenInRange(int32 start
, int32 end
) {
199 while (!InRange(start
, end
, last_state_
.token
) &&
200 last_state_
.error
== gpu::error::kNoError
) {
201 MakeProgressAndUpdateState();
206 void CommandBufferClientImpl::WaitForGetOffsetInRange(int32 start
, int32 end
) {
208 while (!InRange(start
, end
, last_state_
.get_offset
) &&
209 last_state_
.error
== gpu::error::kNoError
) {
210 MakeProgressAndUpdateState();
215 void CommandBufferClientImpl::SetGetBuffer(int32 shm_id
) {
216 command_buffer_
->SetGetBuffer(shm_id
);
217 last_put_offset_
= -1;
220 scoped_refptr
<gpu::Buffer
> CommandBufferClientImpl::CreateTransferBuffer(
223 if (size
>= std::numeric_limits
<uint32_t>::max())
227 mojo::ScopedSharedBufferHandle handle
;
228 mojo::ScopedSharedBufferHandle duped
;
229 if (!CreateMapAndDupSharedBuffer(size
, &memory
, &handle
, &duped
)) {
230 if (last_state_
.error
== gpu::error::kNoError
)
231 last_state_
.error
= gpu::error::kLostContext
;
235 *id
= ++next_transfer_buffer_id_
;
237 command_buffer_
->RegisterTransferBuffer(
238 *id
, duped
.Pass(), static_cast<uint32_t>(size
));
240 scoped_ptr
<gpu::BufferBacking
> backing(
241 new MojoBufferBacking(handle
.Pass(), memory
, size
));
242 scoped_refptr
<gpu::Buffer
> buffer(new gpu::Buffer(backing
.Pass()));
246 void CommandBufferClientImpl::DestroyTransferBuffer(int32 id
) {
247 command_buffer_
->DestroyTransferBuffer(id
);
250 gpu::Capabilities
CommandBufferClientImpl::GetCapabilities() {
251 return capabilities_
;
254 int32_t CommandBufferClientImpl::CreateImage(ClientBuffer buffer
,
257 unsigned internalformat
) {
258 int32 new_id
= ++next_image_id_
;
260 mojo::SizePtr size
= mojo::Size::New();
261 size
->width
= static_cast<int32_t>(width
);
262 size
->height
= static_cast<int32_t>(height
);
264 MojoGpuMemoryBufferImpl
* gpu_memory_buffer
=
265 MojoGpuMemoryBufferImpl::FromClientBuffer(buffer
);
266 gfx::GpuMemoryBufferHandle handle
= gpu_memory_buffer
->GetHandle();
268 bool requires_sync_point
= false;
269 base::SharedMemoryHandle dupd_handle
=
270 base::SharedMemory::DuplicateHandle(handle
.handle
);
272 HANDLE platform_handle
= dupd_handle
;
274 int platform_handle
= dupd_handle
.fd
;
277 if (handle
.type
!= gfx::SHARED_MEMORY_BUFFER
) {
278 requires_sync_point
= true;
283 MojoHandle mojo_handle
= MOJO_HANDLE_INVALID
;
284 MojoResult create_result
= MojoCreatePlatformHandleWrapper(
285 platform_handle
, &mojo_handle
);
286 if (create_result
!= MOJO_RESULT_OK
) {
290 mojo::ScopedHandle scoped_handle
;
291 scoped_handle
.reset(mojo::Handle(mojo_handle
));
292 command_buffer_
->CreateImage(
293 new_id
, scoped_handle
.Pass(), handle
.type
, size
.Pass(),
294 static_cast<int32_t>(gpu_memory_buffer
->GetFormat()), internalformat
);
295 if (requires_sync_point
) {
297 // TODO(jam): need to support this if we support types other than
298 // SHARED_MEMORY_BUFFER.
299 //gpu_memory_buffer_manager->SetDestructionSyncPoint(gpu_memory_buffer,
300 // InsertSyncPoint());
306 void CommandBufferClientImpl::DestroyImage(int32 id
) {
307 command_buffer_
->DestroyImage(id
);
310 int32_t CommandBufferClientImpl::CreateGpuMemoryBufferImage(
313 unsigned internalformat
,
315 scoped_ptr
<gfx::GpuMemoryBuffer
> buffer(MojoGpuMemoryBufferImpl::Create(
316 gfx::Size(static_cast<int>(width
), static_cast<int>(height
)),
317 gpu::ImageFactory::DefaultBufferFormatForImageFormat(internalformat
),
318 gpu::ImageFactory::ImageUsageToGpuMemoryBufferUsage(usage
)));
322 return CreateImage(buffer
->AsClientBuffer(), width
, height
, internalformat
);
325 uint32_t CommandBufferClientImpl::InsertSyncPoint() {
326 command_buffer_
->InsertSyncPoint(true);
327 return sync_point_client_impl_
->WaitForInsertSyncPoint();
330 uint32_t CommandBufferClientImpl::InsertFutureSyncPoint() {
331 command_buffer_
->InsertSyncPoint(false);
332 return sync_point_client_impl_
->WaitForInsertSyncPoint();
335 void CommandBufferClientImpl::RetireSyncPoint(uint32_t sync_point
) {
336 command_buffer_
->RetireSyncPoint(sync_point
);
339 void CommandBufferClientImpl::SignalSyncPoint(uint32_t sync_point
,
340 const base::Closure
& callback
) {
344 void CommandBufferClientImpl::SignalQuery(uint32_t query
,
345 const base::Closure
& callback
) {
350 void CommandBufferClientImpl::SetSurfaceVisible(bool visible
) {
355 uint32_t CommandBufferClientImpl::CreateStreamTexture(uint32_t texture_id
) {
361 void CommandBufferClientImpl::DidLoseContext(int32_t lost_reason
) {
362 last_state_
.error
= gpu::error::kLostContext
;
363 last_state_
.context_lost_reason
=
364 static_cast<gpu::error::ContextLostReason
>(lost_reason
);
365 delegate_
->ContextLost();
368 void CommandBufferClientImpl::TryUpdateState() {
369 if (last_state_
.error
== gpu::error::kNoError
)
370 shared_state()->Read(&last_state_
);
373 void CommandBufferClientImpl::MakeProgressAndUpdateState() {
374 command_buffer_
->MakeProgress(last_state_
.get_offset
);
376 mojo::CommandBufferStatePtr state
= sync_client_impl_
->WaitForProgress();
378 VLOG(1) << "Channel encountered error while waiting for command buffer";
379 // TODO(piman): is it ok for this to re-enter?
380 DidLoseContext(gpu::error::kUnknown
);
384 if (state
->generation
- last_state_
.generation
< 0x80000000U
)
385 last_state_
= state
.To
<State
>();
388 void CommandBufferClientImpl::SetLock(base::Lock
* lock
) {
391 bool CommandBufferClientImpl::IsGpuChannelLost() {
392 // This is only possible for out-of-process command buffers.