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/mus/gles2/command_buffer_type_conversions.h"
12 #include "components/mus/gles2/mojo_buffer_backing.h"
13 #include "components/mus/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 std::vector
<int32_t>& attribs
,
122 const MojoAsyncWaiter
* async_waiter
,
123 mojo::ScopedMessagePipeHandle command_buffer_handle
)
124 : delegate_(delegate
),
126 observer_binding_(this),
128 last_put_offset_(-1),
129 next_transfer_buffer_id_(0),
131 async_waiter_(async_waiter
) {
132 command_buffer_
.Bind(mojo::InterfacePtrInfo
<mojo::CommandBuffer
>(
133 command_buffer_handle
.Pass(), 0u),
135 command_buffer_
.set_connection_error_handler(
136 [this]() { DidLoseContext(gpu::error::kUnknown
); });
139 CommandBufferClientImpl::~CommandBufferClientImpl() {}
141 bool CommandBufferClientImpl::Initialize() {
142 const size_t kSharedStateSize
= sizeof(gpu::CommandBufferSharedState
);
144 mojo::ScopedSharedBufferHandle duped
;
145 bool result
= CreateMapAndDupSharedBuffer(
146 kSharedStateSize
, &memory
, &shared_state_handle_
, &duped
);
150 shared_state_
= static_cast<gpu::CommandBufferSharedState
*>(memory
);
152 shared_state()->Initialize();
154 mojo::CommandBufferSyncClientPtr sync_client
;
155 sync_client_impl_
.reset(new SyncClientImpl(&sync_client
, async_waiter_
));
157 mojo::CommandBufferSyncPointClientPtr sync_point_client
;
158 sync_point_client_impl_
.reset(
159 new SyncPointClientImpl(&sync_point_client
, async_waiter_
));
161 mojo::CommandBufferLostContextObserverPtr observer_ptr
;
162 observer_binding_
.Bind(GetProxy(&observer_ptr
), async_waiter_
);
163 command_buffer_
->Initialize(sync_client
.Pass(),
164 sync_point_client
.Pass(),
167 mojo::Array
<int32_t>::From(attribs_
));
169 // Wait for DidInitialize to come on the sync client pipe.
170 if (!sync_client_impl_
->WaitForInitialization()) {
171 VLOG(1) << "Channel encountered error while creating command buffer";
174 capabilities_
= sync_client_impl_
->GetCapabilities();
178 gpu::CommandBuffer::State
CommandBufferClientImpl::GetLastState() {
182 int32
CommandBufferClientImpl::GetLastToken() {
184 return last_state_
.token
;
187 void CommandBufferClientImpl::Flush(int32 put_offset
) {
188 if (last_put_offset_
== put_offset
)
191 last_put_offset_
= put_offset
;
192 command_buffer_
->Flush(put_offset
);
195 void CommandBufferClientImpl::OrderingBarrier(int32_t put_offset
) {
196 // TODO(jamesr): Implement this more efficiently.
200 void CommandBufferClientImpl::WaitForTokenInRange(int32 start
, int32 end
) {
202 while (!InRange(start
, end
, last_state_
.token
) &&
203 last_state_
.error
== gpu::error::kNoError
) {
204 MakeProgressAndUpdateState();
209 void CommandBufferClientImpl::WaitForGetOffsetInRange(int32 start
, int32 end
) {
211 while (!InRange(start
, end
, last_state_
.get_offset
) &&
212 last_state_
.error
== gpu::error::kNoError
) {
213 MakeProgressAndUpdateState();
218 void CommandBufferClientImpl::SetGetBuffer(int32 shm_id
) {
219 command_buffer_
->SetGetBuffer(shm_id
);
220 last_put_offset_
= -1;
223 scoped_refptr
<gpu::Buffer
> CommandBufferClientImpl::CreateTransferBuffer(
226 if (size
>= std::numeric_limits
<uint32_t>::max())
230 mojo::ScopedSharedBufferHandle handle
;
231 mojo::ScopedSharedBufferHandle duped
;
232 if (!CreateMapAndDupSharedBuffer(size
, &memory
, &handle
, &duped
)) {
233 if (last_state_
.error
== gpu::error::kNoError
)
234 last_state_
.error
= gpu::error::kLostContext
;
238 *id
= ++next_transfer_buffer_id_
;
240 command_buffer_
->RegisterTransferBuffer(
241 *id
, duped
.Pass(), static_cast<uint32_t>(size
));
243 scoped_ptr
<gpu::BufferBacking
> backing(
244 new mus::MojoBufferBacking(handle
.Pass(), memory
, size
));
245 scoped_refptr
<gpu::Buffer
> buffer(new gpu::Buffer(backing
.Pass()));
249 void CommandBufferClientImpl::DestroyTransferBuffer(int32 id
) {
250 command_buffer_
->DestroyTransferBuffer(id
);
253 gpu::Capabilities
CommandBufferClientImpl::GetCapabilities() {
254 return capabilities_
;
257 int32_t CommandBufferClientImpl::CreateImage(ClientBuffer buffer
,
260 unsigned internalformat
) {
261 int32 new_id
= ++next_image_id_
;
263 mojo::SizePtr size
= mojo::Size::New();
264 size
->width
= static_cast<int32_t>(width
);
265 size
->height
= static_cast<int32_t>(height
);
267 mus::MojoGpuMemoryBufferImpl
* gpu_memory_buffer
=
268 mus::MojoGpuMemoryBufferImpl::FromClientBuffer(buffer
);
269 gfx::GpuMemoryBufferHandle handle
= gpu_memory_buffer
->GetHandle();
271 bool requires_sync_point
= false;
272 base::SharedMemoryHandle dupd_handle
=
273 base::SharedMemory::DuplicateHandle(handle
.handle
);
275 HANDLE platform_handle
= dupd_handle
;
277 int platform_handle
= dupd_handle
.fd
;
280 if (handle
.type
!= gfx::SHARED_MEMORY_BUFFER
) {
281 requires_sync_point
= true;
286 MojoHandle mojo_handle
= MOJO_HANDLE_INVALID
;
287 MojoResult create_result
= MojoCreatePlatformHandleWrapper(
288 platform_handle
, &mojo_handle
);
289 if (create_result
!= MOJO_RESULT_OK
) {
293 mojo::ScopedHandle scoped_handle
;
294 scoped_handle
.reset(mojo::Handle(mojo_handle
));
295 command_buffer_
->CreateImage(
296 new_id
, scoped_handle
.Pass(), handle
.type
, size
.Pass(),
297 static_cast<int32_t>(gpu_memory_buffer
->GetFormat()), internalformat
);
298 if (requires_sync_point
) {
300 // TODO(jam): need to support this if we support types other than
301 // SHARED_MEMORY_BUFFER.
302 //gpu_memory_buffer_manager->SetDestructionSyncPoint(gpu_memory_buffer,
303 // InsertSyncPoint());
309 void CommandBufferClientImpl::DestroyImage(int32 id
) {
310 command_buffer_
->DestroyImage(id
);
313 int32_t CommandBufferClientImpl::CreateGpuMemoryBufferImage(
316 unsigned internalformat
,
318 scoped_ptr
<gfx::GpuMemoryBuffer
> buffer(mus::MojoGpuMemoryBufferImpl::Create(
319 gfx::Size(static_cast<int>(width
), static_cast<int>(height
)),
320 gpu::ImageFactory::DefaultBufferFormatForImageFormat(internalformat
),
321 gpu::ImageFactory::ImageUsageToGpuMemoryBufferUsage(usage
)));
325 return CreateImage(buffer
->AsClientBuffer(), width
, height
, internalformat
);
328 uint32_t CommandBufferClientImpl::InsertSyncPoint() {
329 command_buffer_
->InsertSyncPoint(true);
330 return sync_point_client_impl_
->WaitForInsertSyncPoint();
333 uint32_t CommandBufferClientImpl::InsertFutureSyncPoint() {
334 command_buffer_
->InsertSyncPoint(false);
335 return sync_point_client_impl_
->WaitForInsertSyncPoint();
338 void CommandBufferClientImpl::RetireSyncPoint(uint32_t sync_point
) {
339 command_buffer_
->RetireSyncPoint(sync_point
);
342 void CommandBufferClientImpl::SignalSyncPoint(uint32_t sync_point
,
343 const base::Closure
& callback
) {
347 void CommandBufferClientImpl::SignalQuery(uint32_t query
,
348 const base::Closure
& callback
) {
353 void CommandBufferClientImpl::SetSurfaceVisible(bool visible
) {
358 uint32_t CommandBufferClientImpl::CreateStreamTexture(uint32_t texture_id
) {
364 void CommandBufferClientImpl::DidLoseContext(int32_t lost_reason
) {
365 last_state_
.error
= gpu::error::kLostContext
;
366 last_state_
.context_lost_reason
=
367 static_cast<gpu::error::ContextLostReason
>(lost_reason
);
368 delegate_
->ContextLost();
371 void CommandBufferClientImpl::TryUpdateState() {
372 if (last_state_
.error
== gpu::error::kNoError
)
373 shared_state()->Read(&last_state_
);
376 void CommandBufferClientImpl::MakeProgressAndUpdateState() {
377 command_buffer_
->MakeProgress(last_state_
.get_offset
);
379 mojo::CommandBufferStatePtr state
= sync_client_impl_
->WaitForProgress();
381 VLOG(1) << "Channel encountered error while waiting for command buffer";
382 // TODO(piman): is it ok for this to re-enter?
383 DidLoseContext(gpu::error::kUnknown
);
387 if (state
->generation
- last_state_
.generation
< 0x80000000U
)
388 last_state_
= state
.To
<State
>();
391 void CommandBufferClientImpl::SetLock(base::Lock
* lock
) {
394 bool CommandBufferClientImpl::IsGpuChannelLost() {
395 // This is only possible for out-of-process command buffers.
399 gpu::CommandBufferNamespace
CommandBufferClientImpl::GetNamespaceID() const {
400 return gpu::CommandBufferNamespace::MOJO
;
403 uint64_t CommandBufferClientImpl::GetCommandBufferID() const {
404 // TODO (rjkroege): This must correspond to the command buffer ID on the
405 // server side. Most likely a combination of the client-specific integer and