blob: ceec30e0622889fa5da3b2a2dc70eea770be7c31 [file] [log] [blame]
[email protected]1bee3982009-12-17 23:15:281// Copyright (c) 2009 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.
[email protected]96449d2c2009-11-25 00:01:324
5// This file contains the implementation of the command buffer helper class.
6
[email protected]9f427322010-03-08 22:58:587#include "../client/cmd_buffer_helper.h"
8#include "../common/command_buffer.h"
[email protected]96449d2c2009-11-25 00:01:329
[email protected]a7a27ace2009-12-12 00:11:2510namespace gpu {
[email protected]96449d2c2009-11-25 00:01:3211
[email protected]96449d2c2009-11-25 00:01:3212CommandBufferHelper::CommandBufferHelper(CommandBuffer* command_buffer)
13 : command_buffer_(command_buffer),
14 entries_(NULL),
[email protected]9310b262010-06-03 16:15:4715 total_entry_count_(0),
16 usable_entry_count_(0),
[email protected]96449d2c2009-11-25 00:01:3217 token_(0),
18 last_token_read_(-1),
19 get_(0),
20 put_(0) {
21}
22
[email protected]b21265f2010-05-12 17:05:1323bool CommandBufferHelper::Initialize(int32 ring_buffer_size) {
[email protected]96449d2c2009-11-25 00:01:3224 ring_buffer_ = command_buffer_->GetRingBuffer();
[email protected]7477ea6f2009-12-22 23:28:1525 if (!ring_buffer_.ptr)
[email protected]96449d2c2009-11-25 00:01:3226 return false;
27
[email protected]c77ea362010-01-29 22:02:3628 CommandBuffer::State state = command_buffer_->GetState();
[email protected]7477ea6f2009-12-22 23:28:1529 entries_ = static_cast<CommandBufferEntry*>(ring_buffer_.ptr);
[email protected]b21265f2010-05-12 17:05:1330 int32 num_ring_buffer_entries = ring_buffer_size / sizeof(CommandBufferEntry);
31 if (num_ring_buffer_entries > state.num_entries) {
32 return false;
33 }
[email protected]9310b262010-06-03 16:15:4734
35 const int32 kJumpEntries =
36 sizeof(cmd::Jump) / sizeof(*entries_); // NOLINT
37
38 total_entry_count_ = num_ring_buffer_entries;
39 usable_entry_count_ = total_entry_count_ - kJumpEntries;
[email protected]c77ea362010-01-29 22:02:3640 put_ = state.put_offset;
41 SynchronizeState(state);
[email protected]96449d2c2009-11-25 00:01:3242 return true;
43}
44
45CommandBufferHelper::~CommandBufferHelper() {
46}
47
48bool CommandBufferHelper::Flush() {
[email protected]c77ea362010-01-29 22:02:3649 CommandBuffer::State state = command_buffer_->Flush(put_);
50 SynchronizeState(state);
[email protected]f7a64ee2010-02-01 22:24:1451 return state.error == error::kNoError;
[email protected]96449d2c2009-11-25 00:01:3252}
53
54// Calls Flush() and then waits until the buffer is empty. Break early if the
55// error is set.
56bool CommandBufferHelper::Finish() {
57 do {
58 // Do not loop forever if the flush fails, meaning the command buffer reader
[email protected]c77ea362010-01-29 22:02:3659 // has shutdown.
[email protected]96449d2c2009-11-25 00:01:3260 if (!Flush())
61 return false;
62 } while (put_ != get_);
63
64 return true;
65}
66
67// Inserts a new token into the command stream. It uses an increasing value
68// scheme so that we don't lose tokens (a token has passed if the current token
69// value is higher than that token). Calls Finish() if the token value wraps,
70// which will be rare.
71int32 CommandBufferHelper::InsertToken() {
72 // Increment token as 31-bit integer. Negative values are used to signal an
73 // error.
74 token_ = (token_ + 1) & 0x7FFFFFFF;
[email protected]67e50772010-01-28 21:50:2475 cmd::SetToken& cmd = GetCmdSpace<cmd::SetToken>();
76 cmd.Init(token_);
[email protected]96449d2c2009-11-25 00:01:3277 if (token_ == 0) {
78 // we wrapped
79 Finish();
[email protected]96449d2c2009-11-25 00:01:3280 DCHECK_EQ(token_, last_token_read_);
81 }
82 return token_;
83}
84
85// Waits until the current token value is greater or equal to the value passed
86// in argument.
87void CommandBufferHelper::WaitForToken(int32 token) {
88 // Return immediately if corresponding InsertToken failed.
89 if (token < 0)
90 return;
91 if (last_token_read_ >= token) return; // fast path.
92 if (token > token_) return; // we wrapped
93 Flush();
[email protected]96449d2c2009-11-25 00:01:3294 while (last_token_read_ < token) {
95 if (get_ == put_) {
[email protected]55874892010-04-21 15:38:5296 LOG(FATAL) << "Empty command buffer while waiting on a token.";
[email protected]96449d2c2009-11-25 00:01:3297 return;
98 }
99 // Do not loop forever if the flush fails, meaning the command buffer reader
100 // has shutdown.
101 if (!Flush())
102 return;
[email protected]96449d2c2009-11-25 00:01:32103 }
104}
105
106// Waits for available entries, basically waiting until get >= put + count + 1.
107// It actually waits for contiguous entries, so it may need to wrap the buffer
[email protected]9310b262010-06-03 16:15:47108// around, adding a jump. Thus this function may change the value of put_. The
109// function will return early if an error occurs, in which case the available
110// space may not be available.
[email protected]96449d2c2009-11-25 00:01:32111void CommandBufferHelper::WaitForAvailableEntries(int32 count) {
[email protected]9310b262010-06-03 16:15:47112 CHECK(count < usable_entry_count_);
113 if (put_ + count > usable_entry_count_) {
[email protected]96449d2c2009-11-25 00:01:32114 // There's not enough room between the current put and the end of the
[email protected]9310b262010-06-03 16:15:47115 // buffer, so we need to wrap. We will add a jump back to the start, but we
116 // need to make sure get wraps first, actually that get is 1 or more (since
117 // put will wrap to 0 after we add the jump).
[email protected]96449d2c2009-11-25 00:01:32118 DCHECK_LE(1, put_);
119 Flush();
120 while (get_ > put_ || get_ == 0) {
121 // Do not loop forever if the flush fails, meaning the command buffer
122 // reader has shutdown.
123 if (!Flush())
124 return;
125 }
[email protected]9310b262010-06-03 16:15:47126 // Insert a jump back to the beginning.
127 cmd::Jump::Set(&entries_[put_], 0);
[email protected]96449d2c2009-11-25 00:01:32128 put_ = 0;
129 }
130 // If we have enough room, return immediatly.
131 if (count <= AvailableEntries()) return;
132 // Otherwise flush, and wait until we do have enough room.
133 Flush();
134 while (AvailableEntries() < count) {
135 // Do not loop forever if the flush fails, meaning the command buffer reader
136 // has shutdown.
137 if (!Flush())
138 return;
139 }
140}
141
142CommandBufferEntry* CommandBufferHelper::GetSpace(uint32 entries) {
143 WaitForAvailableEntries(entries);
144 CommandBufferEntry* space = &entries_[put_];
145 put_ += entries;
[email protected]9310b262010-06-03 16:15:47146 DCHECK_LE(put_, usable_entry_count_);
147 if (put_ == usable_entry_count_) {
148 cmd::Jump::Set(&entries_[put_], 0);
[email protected]7e5bee52010-03-08 18:21:00149 put_ = 0;
150 }
[email protected]96449d2c2009-11-25 00:01:32151 return space;
152}
153
[email protected]f7a64ee2010-02-01 22:24:14154error::Error CommandBufferHelper::GetError() {
[email protected]c77ea362010-01-29 22:02:36155 CommandBuffer::State state = command_buffer_->GetState();
156 SynchronizeState(state);
[email protected]f7a64ee2010-02-01 22:24:14157 return static_cast<error::Error>(state.error);
[email protected]c77ea362010-01-29 22:02:36158}
159
160void CommandBufferHelper::SynchronizeState(CommandBuffer::State state) {
161 get_ = state.get_offset;
162 last_token_read_ = state.token;
[email protected]96449d2c2009-11-25 00:01:32163}
164
[email protected]a7a27ace2009-12-12 00:11:25165} // namespace gpu