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() {
70 return capabilities_
.To
<gpu::Capabilities
>();
74 // CommandBufferSyncClient methods:
75 void DidInitialize(bool success
,
76 mojo::GpuCapabilitiesPtr capabilities
) override
{
77 initialized_successfully_
= success
;
78 capabilities_
= capabilities
.Pass();
80 void DidMakeProgress(mojo::CommandBufferStatePtr state
) override
{
81 command_buffer_state_
= state
.Pass();
84 bool initialized_successfully_
;
85 mojo::GpuCapabilitiesPtr capabilities_
;
86 mojo::CommandBufferStatePtr command_buffer_state_
;
87 mojo::Binding
<mojo::CommandBufferSyncClient
> binding_
;
89 DISALLOW_COPY_AND_ASSIGN(SyncClientImpl
);
92 class CommandBufferClientImpl::SyncPointClientImpl
93 : public mojo::CommandBufferSyncPointClient
{
95 SyncPointClientImpl(mojo::CommandBufferSyncPointClientPtr
* ptr
,
96 const MojoAsyncWaiter
* async_waiter
)
97 : sync_point_(0u), binding_(this, ptr
, async_waiter
) {}
99 uint32_t WaitForInsertSyncPoint() {
100 if (!binding_
.WaitForIncomingMethodCall())
102 uint32_t result
= sync_point_
;
108 void DidInsertSyncPoint(uint32_t sync_point
) override
{
109 sync_point_
= sync_point
;
112 uint32_t sync_point_
;
114 mojo::Binding
<mojo::CommandBufferSyncPointClient
> binding_
;
117 CommandBufferClientImpl::CommandBufferClientImpl(
118 CommandBufferDelegate
* delegate
,
119 const MojoAsyncWaiter
* async_waiter
,
120 mojo::ScopedMessagePipeHandle command_buffer_handle
)
121 : delegate_(delegate
),
122 observer_binding_(this),
124 last_put_offset_(-1),
125 next_transfer_buffer_id_(0),
127 async_waiter_(async_waiter
) {
128 command_buffer_
.Bind(mojo::InterfacePtrInfo
<mojo::CommandBuffer
>(
129 command_buffer_handle
.Pass(), 0u),
131 command_buffer_
.set_connection_error_handler(
132 [this]() { DidLoseContext(gpu::error::kUnknown
); });
135 CommandBufferClientImpl::~CommandBufferClientImpl() {}
137 bool CommandBufferClientImpl::Initialize() {
138 const size_t kSharedStateSize
= sizeof(gpu::CommandBufferSharedState
);
140 mojo::ScopedSharedBufferHandle duped
;
141 bool result
= CreateMapAndDupSharedBuffer(
142 kSharedStateSize
, &memory
, &shared_state_handle_
, &duped
);
146 shared_state_
= static_cast<gpu::CommandBufferSharedState
*>(memory
);
148 shared_state()->Initialize();
150 mojo::CommandBufferSyncClientPtr sync_client
;
151 sync_client_impl_
.reset(new SyncClientImpl(&sync_client
, async_waiter_
));
153 mojo::CommandBufferSyncPointClientPtr sync_point_client
;
154 sync_point_client_impl_
.reset(
155 new SyncPointClientImpl(&sync_point_client
, async_waiter_
));
157 mojo::CommandBufferLostContextObserverPtr observer_ptr
;
158 observer_binding_
.Bind(GetProxy(&observer_ptr
), async_waiter_
);
159 command_buffer_
->Initialize(sync_client
.Pass(),
160 sync_point_client
.Pass(),
164 // Wait for DidInitialize to come on the sync client pipe.
165 if (!sync_client_impl_
->WaitForInitialization()) {
166 VLOG(1) << "Channel encountered error while creating command buffer";
169 capabilities_
= sync_client_impl_
->GetCapabilities();
173 gpu::CommandBuffer::State
CommandBufferClientImpl::GetLastState() {
177 int32
CommandBufferClientImpl::GetLastToken() {
179 return last_state_
.token
;
182 void CommandBufferClientImpl::Flush(int32 put_offset
) {
183 if (last_put_offset_
== put_offset
)
186 last_put_offset_
= put_offset
;
187 command_buffer_
->Flush(put_offset
);
190 void CommandBufferClientImpl::OrderingBarrier(int32_t put_offset
) {
191 // TODO(jamesr): Implement this more efficiently.
195 void CommandBufferClientImpl::WaitForTokenInRange(int32 start
, int32 end
) {
197 while (!InRange(start
, end
, last_state_
.token
) &&
198 last_state_
.error
== gpu::error::kNoError
) {
199 MakeProgressAndUpdateState();
204 void CommandBufferClientImpl::WaitForGetOffsetInRange(int32 start
, int32 end
) {
206 while (!InRange(start
, end
, last_state_
.get_offset
) &&
207 last_state_
.error
== gpu::error::kNoError
) {
208 MakeProgressAndUpdateState();
213 void CommandBufferClientImpl::SetGetBuffer(int32 shm_id
) {
214 command_buffer_
->SetGetBuffer(shm_id
);
215 last_put_offset_
= -1;
218 scoped_refptr
<gpu::Buffer
> CommandBufferClientImpl::CreateTransferBuffer(
221 if (size
>= std::numeric_limits
<uint32_t>::max())
225 mojo::ScopedSharedBufferHandle handle
;
226 mojo::ScopedSharedBufferHandle duped
;
227 if (!CreateMapAndDupSharedBuffer(size
, &memory
, &handle
, &duped
)) {
228 if (last_state_
.error
== gpu::error::kNoError
)
229 last_state_
.error
= gpu::error::kLostContext
;
233 *id
= ++next_transfer_buffer_id_
;
235 command_buffer_
->RegisterTransferBuffer(
236 *id
, duped
.Pass(), static_cast<uint32_t>(size
));
238 scoped_ptr
<gpu::BufferBacking
> backing(
239 new MojoBufferBacking(handle
.Pass(), memory
, size
));
240 scoped_refptr
<gpu::Buffer
> buffer(new gpu::Buffer(backing
.Pass()));
244 void CommandBufferClientImpl::DestroyTransferBuffer(int32 id
) {
245 command_buffer_
->DestroyTransferBuffer(id
);
248 gpu::Capabilities
CommandBufferClientImpl::GetCapabilities() {
249 return capabilities_
;
252 int32_t CommandBufferClientImpl::CreateImage(ClientBuffer buffer
,
255 unsigned internalformat
) {
256 int32 new_id
= ++next_image_id_
;
258 mojo::SizePtr size
= mojo::Size::New();
259 size
->width
= static_cast<int32_t>(width
);
260 size
->height
= static_cast<int32_t>(height
);
262 MojoGpuMemoryBufferImpl
* gpu_memory_buffer
=
263 MojoGpuMemoryBufferImpl::FromClientBuffer(buffer
);
264 gfx::GpuMemoryBufferHandle handle
= gpu_memory_buffer
->GetHandle();
266 bool requires_sync_point
= false;
267 base::SharedMemoryHandle dupd_handle
=
268 base::SharedMemory::DuplicateHandle(handle
.handle
);
270 HANDLE platform_handle
= dupd_handle
;
272 int platform_handle
= dupd_handle
.fd
;
275 if (handle
.type
!= gfx::SHARED_MEMORY_BUFFER
) {
276 requires_sync_point
= true;
281 MojoHandle mojo_handle
= MOJO_HANDLE_INVALID
;
282 MojoResult create_result
= MojoCreatePlatformHandleWrapper(
283 platform_handle
, &mojo_handle
);
284 if (create_result
!= MOJO_RESULT_OK
) {
288 mojo::ScopedHandle scoped_handle
;
289 scoped_handle
.reset(mojo::Handle(mojo_handle
));
290 command_buffer_
->CreateImage(
291 new_id
, scoped_handle
.Pass(), handle
.type
, size
.Pass(),
292 static_cast<int32_t>(gpu_memory_buffer
->GetFormat()), internalformat
);
293 if (requires_sync_point
) {
295 // TODO(jam): need to support this if we support types other than
296 // SHARED_MEMORY_BUFFER.
297 //gpu_memory_buffer_manager->SetDestructionSyncPoint(gpu_memory_buffer,
298 // InsertSyncPoint());
304 void CommandBufferClientImpl::DestroyImage(int32 id
) {
305 command_buffer_
->DestroyImage(id
);
308 int32_t CommandBufferClientImpl::CreateGpuMemoryBufferImage(
311 unsigned internalformat
,
313 scoped_ptr
<gfx::GpuMemoryBuffer
> buffer(MojoGpuMemoryBufferImpl::Create(
314 gfx::Size(static_cast<int>(width
), static_cast<int>(height
)),
315 gpu::ImageFactory::ImageFormatToGpuMemoryBufferFormat(internalformat
),
316 gpu::ImageFactory::ImageUsageToGpuMemoryBufferUsage(usage
)));
320 return CreateImage(buffer
->AsClientBuffer(), width
, height
, internalformat
);
323 uint32_t CommandBufferClientImpl::InsertSyncPoint() {
324 command_buffer_
->InsertSyncPoint(true);
325 return sync_point_client_impl_
->WaitForInsertSyncPoint();
328 uint32_t CommandBufferClientImpl::InsertFutureSyncPoint() {
329 command_buffer_
->InsertSyncPoint(false);
330 return sync_point_client_impl_
->WaitForInsertSyncPoint();
333 void CommandBufferClientImpl::RetireSyncPoint(uint32_t sync_point
) {
334 command_buffer_
->RetireSyncPoint(sync_point
);
337 void CommandBufferClientImpl::SignalSyncPoint(uint32_t sync_point
,
338 const base::Closure
& callback
) {
342 void CommandBufferClientImpl::SignalQuery(uint32_t query
,
343 const base::Closure
& callback
) {
348 void CommandBufferClientImpl::SetSurfaceVisible(bool visible
) {
353 uint32_t CommandBufferClientImpl::CreateStreamTexture(uint32_t texture_id
) {
359 void CommandBufferClientImpl::DidLoseContext(int32_t lost_reason
) {
360 last_state_
.error
= gpu::error::kLostContext
;
361 last_state_
.context_lost_reason
=
362 static_cast<gpu::error::ContextLostReason
>(lost_reason
);
363 delegate_
->ContextLost();
366 void CommandBufferClientImpl::TryUpdateState() {
367 if (last_state_
.error
== gpu::error::kNoError
)
368 shared_state()->Read(&last_state_
);
371 void CommandBufferClientImpl::MakeProgressAndUpdateState() {
372 command_buffer_
->MakeProgress(last_state_
.get_offset
);
374 mojo::CommandBufferStatePtr state
= sync_client_impl_
->WaitForProgress();
376 VLOG(1) << "Channel encountered error while waiting for command buffer";
377 // TODO(piman): is it ok for this to re-enter?
378 DidLoseContext(gpu::error::kUnknown
);
382 if (state
->generation
- last_state_
.generation
< 0x80000000U
)
383 last_state_
= state
.To
<State
>();
386 void CommandBufferClientImpl::SetLock(base::Lock
* lock
) {
389 bool CommandBufferClientImpl::IsGpuChannelLost() {
390 // This is only possible for out-of-process command buffers.