1// Copyright (c) 2012 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 "gpu/command_buffer/service/command_buffer_service.h"
6
7#include <limits>
8
9#include "base/logging.h"
10#include "base/debug/trace_event.h"
11#include "gpu/command_buffer/common/cmd_buffer_common.h"
12#include "gpu/command_buffer/common/command_buffer_shared.h"
13#include "gpu/command_buffer/service/transfer_buffer_manager.h"
14
15using ::base::SharedMemory;
16
17namespace gpu {
18
19CommandBufferService::CommandBufferService(
20    TransferBufferManagerInterface* transfer_buffer_manager)
21    : ring_buffer_id_(-1),
22      shared_state_(NULL),
23      num_entries_(0),
24      get_offset_(0),
25      put_offset_(0),
26      transfer_buffer_manager_(transfer_buffer_manager),
27      token_(0),
28      generation_(0),
29      error_(error::kNoError),
30      context_lost_reason_(error::kUnknown) {
31}
32
33CommandBufferService::~CommandBufferService() {
34}
35
36bool CommandBufferService::Initialize() {
37  return true;
38}
39
40CommandBufferService::State CommandBufferService::GetState() {
41  State state;
42  state.num_entries = num_entries_;
43  state.get_offset = get_offset_;
44  state.put_offset = put_offset_;
45  state.token = token_;
46  state.error = error_;
47  state.context_lost_reason = context_lost_reason_;
48  state.generation = ++generation_;
49
50  return state;
51}
52
53CommandBufferService::State CommandBufferService::GetLastState() {
54  return GetState();
55}
56
57int32 CommandBufferService::GetLastToken() {
58  return GetState().token;
59}
60
61void CommandBufferService::UpdateState() {
62  if (shared_state_) {
63    CommandBufferService::State state = GetState();
64    shared_state_->Write(state);
65  }
66}
67
68CommandBufferService::State CommandBufferService::FlushSync(
69    int32 put_offset, int32 last_known_get) {
70  if (put_offset < 0 || put_offset > num_entries_) {
71    error_ = gpu::error::kOutOfBounds;
72    return GetState();
73  }
74
75  put_offset_ = put_offset;
76
77  if (!put_offset_change_callback_.is_null())
78    put_offset_change_callback_.Run();
79
80  return GetState();
81}
82
83void CommandBufferService::Flush(int32 put_offset) {
84  if (put_offset < 0 || put_offset > num_entries_) {
85    error_ = gpu::error::kOutOfBounds;
86    return;
87  }
88
89  put_offset_ = put_offset;
90
91  if (!put_offset_change_callback_.is_null())
92    put_offset_change_callback_.Run();
93}
94
95void CommandBufferService::SetGetBuffer(int32 transfer_buffer_id) {
96  DCHECK_EQ(-1, ring_buffer_id_);
97  DCHECK_EQ(put_offset_, get_offset_);  // Only if it's empty.
98  ring_buffer_ = GetTransferBuffer(transfer_buffer_id);
99  DCHECK(ring_buffer_.ptr);
100  ring_buffer_id_ = transfer_buffer_id;
101  num_entries_ = ring_buffer_.size / sizeof(CommandBufferEntry);
102  put_offset_ = 0;
103  SetGetOffset(0);
104  if (!get_buffer_change_callback_.is_null()) {
105    get_buffer_change_callback_.Run(ring_buffer_id_);
106  }
107
108  UpdateState();
109}
110
111bool CommandBufferService::SetSharedStateBuffer(
112    scoped_ptr<base::SharedMemory> shared_state_shm) {
113  shared_state_shm_.reset(shared_state_shm.release());
114  if (!shared_state_shm_->Map(sizeof(*shared_state_)))
115    return false;
116
117  shared_state_ =
118      static_cast<CommandBufferSharedState*>(shared_state_shm_->memory());
119
120  UpdateState();
121  return true;
122}
123
124void CommandBufferService::SetGetOffset(int32 get_offset) {
125  DCHECK(get_offset >= 0 && get_offset < num_entries_);
126  get_offset_ = get_offset;
127}
128
129Buffer CommandBufferService::CreateTransferBuffer(size_t size,
130                                                  int32* id) {
131  *id = -1;
132
133  SharedMemory buffer;
134  if (!buffer.CreateAnonymous(size))
135    return Buffer();
136
137  static int32 next_id = 1;
138  *id = next_id++;
139
140  if (!RegisterTransferBuffer(*id, &buffer, size)) {
141    *id = -1;
142    return Buffer();
143  }
144
145  return GetTransferBuffer(*id);
146}
147
148void CommandBufferService::DestroyTransferBuffer(int32 id) {
149  transfer_buffer_manager_->DestroyTransferBuffer(id);
150  if (id == ring_buffer_id_) {
151    ring_buffer_id_ = -1;
152    ring_buffer_ = Buffer();
153    num_entries_ = 0;
154    get_offset_ = 0;
155    put_offset_ = 0;
156  }
157}
158
159Buffer CommandBufferService::GetTransferBuffer(int32 id) {
160  return transfer_buffer_manager_->GetTransferBuffer(id);
161}
162
163bool CommandBufferService::RegisterTransferBuffer(
164    int32 id,
165    base::SharedMemory* shared_memory,
166    size_t size) {
167  return transfer_buffer_manager_->RegisterTransferBuffer(id,
168                                                          shared_memory,
169                                                          size);
170}
171
172void CommandBufferService::SetToken(int32 token) {
173  token_ = token;
174  UpdateState();
175}
176
177void CommandBufferService::SetParseError(error::Error error) {
178  if (error_ == error::kNoError) {
179    error_ = error;
180    if (!parse_error_callback_.is_null())
181      parse_error_callback_.Run();
182  }
183}
184
185void CommandBufferService::SetContextLostReason(
186    error::ContextLostReason reason) {
187  context_lost_reason_ = reason;
188}
189
190void CommandBufferService::SetPutOffsetChangeCallback(
191    const base::Closure& callback) {
192  put_offset_change_callback_ = callback;
193}
194
195void CommandBufferService::SetGetBufferChangeCallback(
196    const GetBufferChangedCallback& callback) {
197  get_buffer_change_callback_ = callback;
198}
199
200void CommandBufferService::SetParseErrorCallback(
201    const base::Closure& callback) {
202  parse_error_callback_ = callback;
203}
204
205}  // namespace gpu
206