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::GetLastState() {
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
53int32 CommandBufferService::GetLastToken() {
54  return GetLastState().token;
55}
56
57void CommandBufferService::UpdateState() {
58  if (shared_state_) {
59    CommandBufferService::State state = GetLastState();
60    shared_state_->Write(state);
61  }
62}
63
64void CommandBufferService::WaitForTokenInRange(int32 start, int32 end) {
65  DCHECK(error_ != error::kNoError || InRange(start, end, token_));
66}
67
68void CommandBufferService::WaitForGetOffsetInRange(int32 start, int32 end) {
69  DCHECK(error_ != error::kNoError || InRange(start, end, get_offset_));
70}
71
72void CommandBufferService::Flush(int32 put_offset) {
73  if (put_offset < 0 || put_offset > num_entries_) {
74    error_ = gpu::error::kOutOfBounds;
75    return;
76  }
77
78  put_offset_ = put_offset;
79
80  if (!put_offset_change_callback_.is_null())
81    put_offset_change_callback_.Run();
82}
83
84void CommandBufferService::SetGetBuffer(int32 transfer_buffer_id) {
85  DCHECK_EQ(-1, ring_buffer_id_);
86  DCHECK_EQ(put_offset_, get_offset_);  // Only if it's empty.
87  // If the buffer is invalid we handle it gracefully.
88  // This means ring_buffer_ can be NULL.
89  ring_buffer_ = GetTransferBuffer(transfer_buffer_id);
90  ring_buffer_id_ = transfer_buffer_id;
91  int32 size = ring_buffer_.get() ? ring_buffer_->size() : 0;
92  num_entries_ = size / sizeof(CommandBufferEntry);
93  put_offset_ = 0;
94  SetGetOffset(0);
95  if (!get_buffer_change_callback_.is_null()) {
96    get_buffer_change_callback_.Run(ring_buffer_id_);
97  }
98
99  UpdateState();
100}
101
102void CommandBufferService::SetSharedStateBuffer(
103    scoped_ptr<BufferBacking> shared_state_buffer) {
104  shared_state_buffer_ = shared_state_buffer.Pass();
105  DCHECK(shared_state_buffer_->GetSize() >= sizeof(*shared_state_));
106
107  shared_state_ =
108      static_cast<CommandBufferSharedState*>(shared_state_buffer_->GetMemory());
109
110  UpdateState();
111}
112
113void CommandBufferService::SetGetOffset(int32 get_offset) {
114  DCHECK(get_offset >= 0 && get_offset < num_entries_);
115  get_offset_ = get_offset;
116}
117
118scoped_refptr<Buffer> CommandBufferService::CreateTransferBuffer(size_t size,
119                                                                 int32* id) {
120  *id = -1;
121
122  scoped_ptr<SharedMemory> shared_memory(new SharedMemory());
123  if (!shared_memory->CreateAndMapAnonymous(size))
124    return NULL;
125
126  static int32 next_id = 1;
127  *id = next_id++;
128
129  if (!RegisterTransferBuffer(
130          *id, MakeBackingFromSharedMemory(shared_memory.Pass(), size))) {
131    *id = -1;
132    return NULL;
133  }
134
135  return GetTransferBuffer(*id);
136}
137
138void CommandBufferService::DestroyTransferBuffer(int32 id) {
139  transfer_buffer_manager_->DestroyTransferBuffer(id);
140  if (id == ring_buffer_id_) {
141    ring_buffer_id_ = -1;
142    ring_buffer_ = NULL;
143    num_entries_ = 0;
144    get_offset_ = 0;
145    put_offset_ = 0;
146  }
147}
148
149scoped_refptr<Buffer> CommandBufferService::GetTransferBuffer(int32 id) {
150  return transfer_buffer_manager_->GetTransferBuffer(id);
151}
152
153bool CommandBufferService::RegisterTransferBuffer(
154    int32 id,
155    scoped_ptr<BufferBacking> buffer) {
156  return transfer_buffer_manager_->RegisterTransferBuffer(id, buffer.Pass());
157}
158
159void CommandBufferService::SetToken(int32 token) {
160  token_ = token;
161  UpdateState();
162}
163
164void CommandBufferService::SetParseError(error::Error error) {
165  if (error_ == error::kNoError) {
166    error_ = error;
167    if (!parse_error_callback_.is_null())
168      parse_error_callback_.Run();
169  }
170}
171
172void CommandBufferService::SetContextLostReason(
173    error::ContextLostReason reason) {
174  context_lost_reason_ = reason;
175}
176
177void CommandBufferService::SetPutOffsetChangeCallback(
178    const base::Closure& callback) {
179  put_offset_change_callback_ = callback;
180}
181
182void CommandBufferService::SetGetBufferChangeCallback(
183    const GetBufferChangedCallback& callback) {
184  get_buffer_change_callback_ = callback;
185}
186
187void CommandBufferService::SetParseErrorCallback(
188    const base::Closure& callback) {
189  parse_error_callback_ = callback;
190}
191
192}  // namespace gpu
193