blob: 0651ee630cf2b838e29dd8913212c9601718b5af [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
7#include "gpu/command_buffer/client/cmd_buffer_helper.h"
8#include "gpu/command_buffer/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),
15 entry_count_(0),
16 token_(0),
17 last_token_read_(-1),
18 get_(0),
19 put_(0) {
20}
21
22bool CommandBufferHelper::Initialize() {
23 ring_buffer_ = command_buffer_->GetRingBuffer();
[email protected]7477ea6f2009-12-22 23:28:1524 if (!ring_buffer_.ptr)
[email protected]96449d2c2009-11-25 00:01:3225 return false;
26
[email protected]7477ea6f2009-12-22 23:28:1527 entries_ = static_cast<CommandBufferEntry*>(ring_buffer_.ptr);
[email protected]96449d2c2009-11-25 00:01:3228 entry_count_ = command_buffer_->GetSize();
29 get_ = command_buffer_->GetGetOffset();
30 put_ = command_buffer_->GetPutOffset();
31 last_token_read_ = command_buffer_->GetToken();
32
33 return true;
34}
35
36CommandBufferHelper::~CommandBufferHelper() {
37}
38
39bool CommandBufferHelper::Flush() {
40 get_ = command_buffer_->SyncOffsets(put_);
41 return !command_buffer_->GetErrorStatus();
42}
43
44// Calls Flush() and then waits until the buffer is empty. Break early if the
45// error is set.
46bool CommandBufferHelper::Finish() {
47 do {
48 // Do not loop forever if the flush fails, meaning the command buffer reader
49 // has shutdown).
50 if (!Flush())
51 return false;
52 } while (put_ != get_);
53
54 return true;
55}
56
57// Inserts a new token into the command stream. It uses an increasing value
58// scheme so that we don't lose tokens (a token has passed if the current token
59// value is higher than that token). Calls Finish() if the token value wraps,
60// which will be rare.
61int32 CommandBufferHelper::InsertToken() {
62 // Increment token as 31-bit integer. Negative values are used to signal an
63 // error.
64 token_ = (token_ + 1) & 0x7FFFFFFF;
[email protected]67e50772010-01-28 21:50:2465 cmd::SetToken& cmd = GetCmdSpace<cmd::SetToken>();
66 cmd.Init(token_);
[email protected]96449d2c2009-11-25 00:01:3267 if (token_ == 0) {
68 // we wrapped
69 Finish();
70 last_token_read_ = command_buffer_->GetToken();
71 DCHECK_EQ(token_, last_token_read_);
72 }
73 return token_;
74}
75
76// Waits until the current token value is greater or equal to the value passed
77// in argument.
78void CommandBufferHelper::WaitForToken(int32 token) {
79 // Return immediately if corresponding InsertToken failed.
80 if (token < 0)
81 return;
82 if (last_token_read_ >= token) return; // fast path.
83 if (token > token_) return; // we wrapped
84 Flush();
85 last_token_read_ = command_buffer_->GetToken();
86 while (last_token_read_ < token) {
87 if (get_ == put_) {
88 LOG(FATAL) << "Empty command buffer while waiting on a token.";
89 return;
90 }
91 // Do not loop forever if the flush fails, meaning the command buffer reader
92 // has shutdown.
93 if (!Flush())
94 return;
95 last_token_read_ = command_buffer_->GetToken();
96 }
97}
98
99// Waits for available entries, basically waiting until get >= put + count + 1.
100// It actually waits for contiguous entries, so it may need to wrap the buffer
101// around, adding noops. Thus this function may change the value of put_.
102// The function will return early if an error occurs, in which case the
103// available space may not be available.
104void CommandBufferHelper::WaitForAvailableEntries(int32 count) {
105 CHECK(count < entry_count_);
106 if (put_ + count > entry_count_) {
107 // There's not enough room between the current put and the end of the
108 // buffer, so we need to wrap. We will add noops all the way to the end,
109 // but we need to make sure get wraps first, actually that get is 1 or
110 // more (since put will wrap to 0 after we add the noops).
111 DCHECK_LE(1, put_);
112 Flush();
113 while (get_ > put_ || get_ == 0) {
114 // Do not loop forever if the flush fails, meaning the command buffer
115 // reader has shutdown.
116 if (!Flush())
117 return;
118 }
[email protected]67e50772010-01-28 21:50:24119 // Insert Noops to fill out buffer.
120 int32 num_entries = entry_count_ - put_;
121 while (num_entries > 0) {
122 int32 num_to_skip = std::min(CommandHeader::kMaxSize, num_entries);
123 cmd::Noop::Set(&entries_[put_], num_to_skip);
124 put_ += num_to_skip;
125 num_entries -= num_to_skip;
[email protected]96449d2c2009-11-25 00:01:32126 }
127 put_ = 0;
128 }
129 // If we have enough room, return immediatly.
130 if (count <= AvailableEntries()) return;
131 // Otherwise flush, and wait until we do have enough room.
132 Flush();
133 while (AvailableEntries() < count) {
134 // Do not loop forever if the flush fails, meaning the command buffer reader
135 // has shutdown.
136 if (!Flush())
137 return;
138 }
139}
140
141CommandBufferEntry* CommandBufferHelper::GetSpace(uint32 entries) {
142 WaitForAvailableEntries(entries);
143 CommandBufferEntry* space = &entries_[put_];
144 put_ += entries;
145 return space;
146}
147
148parse_error::ParseError CommandBufferHelper::GetParseError() {
149 int32 parse_error = command_buffer_->ResetParseError();
150 return static_cast<parse_error::ParseError>(parse_error);
151}
152
[email protected]a7a27ace2009-12-12 00:11:25153} // namespace gpu