OLD | NEW |
---|---|
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // This file contains the implementation of the command buffer helper class. | 5 // This file contains the implementation of the command buffer helper class. |
6 | 6 |
7 #include "../client/cmd_buffer_helper.h" | 7 #include "../client/cmd_buffer_helper.h" |
8 #include "../common/command_buffer.h" | 8 #include "../common/command_buffer.h" |
9 | 9 |
10 namespace gpu { | 10 namespace gpu { |
11 | 11 |
12 CommandBufferHelper::CommandBufferHelper(CommandBuffer* command_buffer) | 12 CommandBufferHelper::CommandBufferHelper(CommandBuffer* command_buffer) |
13 : command_buffer_(command_buffer), | 13 : command_buffer_(command_buffer), |
14 entries_(NULL), | 14 entries_(NULL), |
15 total_entry_count_(0), | 15 total_entry_count_(0), |
16 usable_entry_count_(0), | 16 usable_entry_count_(0), |
17 token_(0), | 17 token_(0), |
18 last_token_read_(-1), | 18 last_token_read_(-1), |
19 get_(0), | 19 get_(0), |
20 put_(0) { | 20 put_(0), |
21 last_put_sent_(0) { | |
21 } | 22 } |
22 | 23 |
23 bool CommandBufferHelper::Initialize(int32 ring_buffer_size) { | 24 bool CommandBufferHelper::Initialize(int32 ring_buffer_size) { |
24 ring_buffer_ = command_buffer_->GetRingBuffer(); | 25 ring_buffer_ = command_buffer_->GetRingBuffer(); |
25 if (!ring_buffer_.ptr) | 26 if (!ring_buffer_.ptr) |
26 return false; | 27 return false; |
27 | 28 |
28 CommandBuffer::State state = command_buffer_->GetState(); | 29 CommandBuffer::State state = command_buffer_->GetState(); |
29 entries_ = static_cast<CommandBufferEntry*>(ring_buffer_.ptr); | 30 entries_ = static_cast<CommandBufferEntry*>(ring_buffer_.ptr); |
30 int32 num_ring_buffer_entries = ring_buffer_size / sizeof(CommandBufferEntry); | 31 int32 num_ring_buffer_entries = ring_buffer_size / sizeof(CommandBufferEntry); |
31 if (num_ring_buffer_entries > state.num_entries) { | 32 if (num_ring_buffer_entries > state.num_entries) { |
32 return false; | 33 return false; |
33 } | 34 } |
34 | 35 |
35 const int32 kJumpEntries = | 36 const int32 kJumpEntries = |
36 sizeof(cmd::Jump) / sizeof(*entries_); // NOLINT | 37 sizeof(cmd::Jump) / sizeof(*entries_); // NOLINT |
37 | 38 |
38 total_entry_count_ = num_ring_buffer_entries; | 39 total_entry_count_ = num_ring_buffer_entries; |
39 usable_entry_count_ = total_entry_count_ - kJumpEntries; | 40 usable_entry_count_ = total_entry_count_ - kJumpEntries; |
40 put_ = state.put_offset; | 41 put_ = state.put_offset; |
41 SynchronizeState(state); | 42 SynchronizeState(state); |
42 return true; | 43 return true; |
43 } | 44 } |
44 | 45 |
45 CommandBufferHelper::~CommandBufferHelper() { | 46 CommandBufferHelper::~CommandBufferHelper() { |
46 } | 47 } |
47 | 48 |
48 bool CommandBufferHelper::Flush() { | 49 bool CommandBufferHelper::FlushSync() { |
49 CommandBuffer::State state = command_buffer_->Flush(put_); | 50 last_put_sent_ = put_; |
51 CommandBuffer::State state = command_buffer_->FlushSync(put_); | |
50 SynchronizeState(state); | 52 SynchronizeState(state); |
51 return state.error == error::kNoError; | 53 return state.error == error::kNoError; |
52 } | 54 } |
53 | 55 |
56 void CommandBufferHelper::Flush() { | |
57 last_put_sent_ = put_; | |
58 command_buffer_->Flush(put_); | |
59 } | |
60 | |
54 // Calls Flush() and then waits until the buffer is empty. Break early if the | 61 // Calls Flush() and then waits until the buffer is empty. Break early if the |
55 // error is set. | 62 // error is set. |
56 bool CommandBufferHelper::Finish() { | 63 bool CommandBufferHelper::Finish() { |
57 do { | 64 do { |
58 // Do not loop forever if the flush fails, meaning the command buffer reader | 65 // Do not loop forever if the flush fails, meaning the command buffer reader |
59 // has shutdown. | 66 // has shutdown. |
60 if (!Flush()) | 67 if (!FlushSync()) |
61 return false; | 68 return false; |
62 } while (put_ != get_); | 69 } while (put_ != get_); |
63 | 70 |
64 return true; | 71 return true; |
65 } | 72 } |
66 | 73 |
67 // Inserts a new token into the command stream. It uses an increasing value | 74 // 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 | 75 // 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, | 76 // value is higher than that token). Calls Finish() if the token value wraps, |
70 // which will be rare. | 77 // which will be rare. |
(...skipping 10 matching lines...) Expand all Loading... | |
81 } | 88 } |
82 return token_; | 89 return token_; |
83 } | 90 } |
84 | 91 |
85 // Waits until the current token value is greater or equal to the value passed | 92 // Waits until the current token value is greater or equal to the value passed |
86 // in argument. | 93 // in argument. |
87 void CommandBufferHelper::WaitForToken(int32 token) { | 94 void CommandBufferHelper::WaitForToken(int32 token) { |
88 // Return immediately if corresponding InsertToken failed. | 95 // Return immediately if corresponding InsertToken failed. |
89 if (token < 0) | 96 if (token < 0) |
90 return; | 97 return; |
91 if (last_token_read_ >= token) return; // fast path. | |
92 if (token > token_) return; // we wrapped | 98 if (token > token_) return; // we wrapped |
93 Flush(); | |
94 while (last_token_read_ < token) { | 99 while (last_token_read_ < token) { |
95 if (get_ == put_) { | 100 if (get_ == put_) { |
96 GPU_LOG(FATAL) << "Empty command buffer while waiting on a token."; | 101 GPU_LOG(FATAL) << "Empty command buffer while waiting on a token."; |
97 return; | 102 return; |
98 } | 103 } |
99 // Do not loop forever if the flush fails, meaning the command buffer reader | 104 // Do not loop forever if the flush fails, meaning the command buffer reader |
100 // has shutdown. | 105 // has shutdown. |
101 if (!Flush()) | 106 if (!FlushSync()) |
102 return; | 107 return; |
103 } | 108 } |
104 } | 109 } |
105 | 110 |
106 // Waits for available entries, basically waiting until get >= put + count + 1. | 111 // 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 | 112 // It actually waits for contiguous entries, so it may need to wrap the buffer |
108 // around, adding a jump. Thus this function may change the value of put_. The | 113 // 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 | 114 // function will return early if an error occurs, in which case the available |
110 // space may not be available. | 115 // space may not be available. |
111 void CommandBufferHelper::WaitForAvailableEntries(int32 count) { | 116 void CommandBufferHelper::WaitForAvailableEntries(int32 count) { |
112 GPU_CHECK(count < usable_entry_count_); | 117 GPU_CHECK(count < usable_entry_count_); |
113 if (put_ + count > usable_entry_count_) { | 118 if (put_ + count > usable_entry_count_) { |
114 // There's not enough room between the current put and the end of the | 119 // There's not enough room between the current put and the end of the |
115 // buffer, so we need to wrap. We will add a jump back to the start, but we | 120 // 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 | 121 // 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). | 122 // put will wrap to 0 after we add the jump). |
118 GPU_DCHECK_LE(1, put_); | 123 GPU_DCHECK_LE(1, put_); |
119 Flush(); | |
120 while (get_ > put_ || get_ == 0) { | 124 while (get_ > put_ || get_ == 0) { |
121 // Do not loop forever if the flush fails, meaning the command buffer | 125 // Do not loop forever if the flush fails, meaning the command buffer |
122 // reader has shutdown. | 126 // reader has shutdown. |
123 if (!Flush()) | 127 if (!FlushSync()) |
124 return; | 128 return; |
125 } | 129 } |
126 // Insert a jump back to the beginning. | 130 // Insert a jump back to the beginning. |
127 cmd::Jump::Set(&entries_[put_], 0); | 131 cmd::Jump::Set(&entries_[put_], 0); |
128 put_ = 0; | 132 put_ = 0; |
129 } | 133 } |
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) { | 134 while (AvailableEntries() < count) { |
135 // Do not loop forever if the flush fails, meaning the command buffer reader | 135 // Do not loop forever if the flush fails, meaning the command buffer reader |
136 // has shutdown. | 136 // has shutdown. |
137 if (!Flush()) | 137 if (!FlushSync()) |
138 return; | 138 return; |
139 } | 139 } |
140 // Force a flush if the buffer is getting half full, or even earlier if the | |
141 // reader is know to be idle. | |
apatrick_chromium
2011/01/14 22:43:32
know -> known
Antoine Labour
2011/01/14 23:17:28
Done.
| |
142 int32 pending = | |
143 (put_ + usable_entry_count_ - last_put_sent_) % usable_entry_count_; | |
144 int32 limit = usable_entry_count_ / ((get_ == last_put_sent_) ? 16 : 2); | |
145 if (pending > limit) { | |
146 Flush(); | |
147 } | |
140 } | 148 } |
141 | 149 |
142 CommandBufferEntry* CommandBufferHelper::GetSpace(uint32 entries) { | 150 CommandBufferEntry* CommandBufferHelper::GetSpace(uint32 entries) { |
143 WaitForAvailableEntries(entries); | 151 WaitForAvailableEntries(entries); |
144 CommandBufferEntry* space = &entries_[put_]; | 152 CommandBufferEntry* space = &entries_[put_]; |
145 put_ += entries; | 153 put_ += entries; |
146 GPU_DCHECK_LE(put_, usable_entry_count_); | 154 GPU_DCHECK_LE(put_, usable_entry_count_); |
147 if (put_ == usable_entry_count_) { | 155 if (put_ == usable_entry_count_) { |
148 cmd::Jump::Set(&entries_[put_], 0); | 156 cmd::Jump::Set(&entries_[put_], 0); |
149 put_ = 0; | 157 put_ = 0; |
150 } | 158 } |
151 return space; | 159 return space; |
152 } | 160 } |
153 | 161 |
154 error::Error CommandBufferHelper::GetError() { | 162 error::Error CommandBufferHelper::GetError() { |
155 CommandBuffer::State state = command_buffer_->GetState(); | 163 CommandBuffer::State state = command_buffer_->GetState(); |
156 SynchronizeState(state); | 164 SynchronizeState(state); |
157 return static_cast<error::Error>(state.error); | 165 return static_cast<error::Error>(state.error); |
158 } | 166 } |
159 | 167 |
160 void CommandBufferHelper::SynchronizeState(CommandBuffer::State state) { | 168 void CommandBufferHelper::SynchronizeState(CommandBuffer::State state) { |
161 get_ = state.get_offset; | 169 get_ = state.get_offset; |
162 last_token_read_ = state.token; | 170 last_token_read_ = state.token; |
163 } | 171 } |
164 | 172 |
165 } // namespace gpu | 173 } // namespace gpu |
OLD | NEW |