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 15 using ::base::SharedMemory; 16 17 namespace gpu { 18 19 CommandBufferService::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 33 CommandBufferService::~CommandBufferService() { 34 } 35 36 bool CommandBufferService::Initialize() { 37 return true; 38 } 39 40 CommandBufferService::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 53 int32 CommandBufferService::GetLastToken() { 54 return GetLastState().token; 55 } 56 57 void CommandBufferService::UpdateState() { 58 if (shared_state_) { 59 CommandBufferService::State state = GetLastState(); 60 shared_state_->Write(state); 61 } 62 } 63 64 void CommandBufferService::WaitForTokenInRange(int32 start, int32 end) { 65 DCHECK(error_ != error::kNoError || InRange(start, end, token_)); 66 } 67 68 void CommandBufferService::WaitForGetOffsetInRange(int32 start, int32 end) { 69 DCHECK(error_ != error::kNoError || InRange(start, end, get_offset_)); 70 } 71 72 void 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 84 void 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 102 void 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 113 void CommandBufferService::SetGetOffset(int32 get_offset) { 114 DCHECK(get_offset >= 0 && get_offset < num_entries_); 115 get_offset_ = get_offset; 116 } 117 118 scoped_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 138 void 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 149 scoped_refptr<Buffer> CommandBufferService::GetTransferBuffer(int32 id) { 150 return transfer_buffer_manager_->GetTransferBuffer(id); 151 } 152 153 bool CommandBufferService::RegisterTransferBuffer( 154 int32 id, 155 scoped_ptr<BufferBacking> buffer) { 156 return transfer_buffer_manager_->RegisterTransferBuffer(id, buffer.Pass()); 157 } 158 159 void CommandBufferService::SetToken(int32 token) { 160 token_ = token; 161 UpdateState(); 162 } 163 164 void 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 172 void CommandBufferService::SetContextLostReason( 173 error::ContextLostReason reason) { 174 context_lost_reason_ = reason; 175 } 176 177 void CommandBufferService::SetPutOffsetChangeCallback( 178 const base::Closure& callback) { 179 put_offset_change_callback_ = callback; 180 } 181 182 void CommandBufferService::SetGetBufferChangeCallback( 183 const GetBufferChangedCallback& callback) { 184 get_buffer_change_callback_ = callback; 185 } 186 187 void CommandBufferService::SetParseErrorCallback( 188 const base::Closure& callback) { 189 parse_error_callback_ = callback; 190 } 191 192 } // namespace gpu 193