blob: b525021da424bf11d2b357adc860f5f3b2f3a66e [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),
[email protected]7d5b8d12011-01-14 23:43:1520 put_(0),
21 last_put_sent_(0) {
[email protected]96449d2c2009-11-25 00:01:3222}
23
[email protected]b21265f2010-05-12 17:05:1324bool CommandBufferHelper::Initialize(int32 ring_buffer_size) {
[email protected]96449d2c2009-11-25 00:01:3225 ring_buffer_ = command_buffer_->GetRingBuffer();
[email protected]7477ea6f2009-12-22 23:28:1526 if (!ring_buffer_.ptr)
[email protected]96449d2c2009-11-25 00:01:3227 return false;
28
[email protected]c77ea362010-01-29 22:02:3629 CommandBuffer::State state = command_buffer_->GetState();
[email protected]7477ea6f2009-12-22 23:28:1530 entries_ = static_cast<CommandBufferEntry*>(ring_buffer_.ptr);
[email protected]b21265f2010-05-12 17:05:1331 int32 num_ring_buffer_entries = ring_buffer_size / sizeof(CommandBufferEntry);
32 if (num_ring_buffer_entries > state.num_entries) {
33 return false;
34 }
[email protected]9310b262010-06-03 16:15:4735
36 const int32 kJumpEntries =
37 sizeof(cmd::Jump) / sizeof(*entries_); // NOLINT
38
39 total_entry_count_ = num_ring_buffer_entries;
40 usable_entry_count_ = total_entry_count_ - kJumpEntries;
[email protected]c77ea362010-01-29 22:02:3641 put_ = state.put_offset;
42 SynchronizeState(state);
[email protected]96449d2c2009-11-25 00:01:3243 return true;
44}
45
46CommandBufferHelper::~CommandBufferHelper() {
47}
48
[email protected]7d5b8d12011-01-14 23:43:1549bool CommandBufferHelper::FlushSync() {
50 last_put_sent_ = put_;
51 CommandBuffer::State state = command_buffer_->FlushSync(put_);
[email protected]c77ea362010-01-29 22:02:3652 SynchronizeState(state);
[email protected]f7a64ee2010-02-01 22:24:1453 return state.error == error::kNoError;
[email protected]96449d2c2009-11-25 00:01:3254}
55
[email protected]7d5b8d12011-01-14 23:43:1556void CommandBufferHelper::Flush() {
57 last_put_sent_ = put_;
58 command_buffer_->Flush(put_);
59}
60
[email protected]96449d2c2009-11-25 00:01:3261// Calls Flush() and then waits until the buffer is empty. Break early if the
62// error is set.
63bool CommandBufferHelper::Finish() {
64 do {
65 // Do not loop forever if the flush fails, meaning the command buffer reader
[email protected]c77ea362010-01-29 22:02:3666 // has shutdown.
[email protected]7d5b8d12011-01-14 23:43:1567 if (!FlushSync())
[email protected]96449d2c2009-11-25 00:01:3268 return false;
69 } while (put_ != get_);
70
71 return true;
72}
73
74// Inserts a new token into the command stream. It uses an increasing value
75// scheme so that we don't lose tokens (a token has passed if the current token
76// value is higher than that token). Calls Finish() if the token value wraps,
77// which will be rare.
78int32 CommandBufferHelper::InsertToken() {
79 // Increment token as 31-bit integer. Negative values are used to signal an
80 // error.
81 token_ = (token_ + 1) & 0x7FFFFFFF;
[email protected]67e50772010-01-28 21:50:2482 cmd::SetToken& cmd = GetCmdSpace<cmd::SetToken>();
83 cmd.Init(token_);
[email protected]96449d2c2009-11-25 00:01:3284 if (token_ == 0) {
85 // we wrapped
86 Finish();
[email protected]20407e92010-09-08 18:31:0887 GPU_DCHECK_EQ(token_, last_token_read_);
[email protected]96449d2c2009-11-25 00:01:3288 }
89 return token_;
90}
91
92// Waits until the current token value is greater or equal to the value passed
93// in argument.
94void CommandBufferHelper::WaitForToken(int32 token) {
95 // Return immediately if corresponding InsertToken failed.
96 if (token < 0)
97 return;
[email protected]96449d2c2009-11-25 00:01:3298 if (token > token_) return; // we wrapped
[email protected]96449d2c2009-11-25 00:01:3299 while (last_token_read_ < token) {
100 if (get_ == put_) {
[email protected]20407e92010-09-08 18:31:08101 GPU_LOG(FATAL) << "Empty command buffer while waiting on a token.";
[email protected]96449d2c2009-11-25 00:01:32102 return;
103 }
104 // Do not loop forever if the flush fails, meaning the command buffer reader
105 // has shutdown.
[email protected]7d5b8d12011-01-14 23:43:15106 if (!FlushSync())
[email protected]96449d2c2009-11-25 00:01:32107 return;
[email protected]96449d2c2009-11-25 00:01:32108 }
109}
110
111// Waits for available entries, basically waiting until get >= put + count + 1.
112// It actually waits for contiguous entries, so it may need to wrap the buffer
[email protected]9310b262010-06-03 16:15:47113// around, adding a jump. Thus this function may change the value of put_. The
114// function will return early if an error occurs, in which case the available
115// space may not be available.
[email protected]96449d2c2009-11-25 00:01:32116void CommandBufferHelper::WaitForAvailableEntries(int32 count) {
[email protected]20407e92010-09-08 18:31:08117 GPU_CHECK(count < usable_entry_count_);
[email protected]9310b262010-06-03 16:15:47118 if (put_ + count > usable_entry_count_) {
[email protected]96449d2c2009-11-25 00:01:32119 // There's not enough room between the current put and the end of the
[email protected]9310b262010-06-03 16:15:47120 // buffer, so we need to wrap. We will add a jump back to the start, but we
121 // need to make sure get wraps first, actually that get is 1 or more (since
122 // put will wrap to 0 after we add the jump).
[email protected]20407e92010-09-08 18:31:08123 GPU_DCHECK_LE(1, put_);
[email protected]96449d2c2009-11-25 00:01:32124 while (get_ > put_ || get_ == 0) {
125 // Do not loop forever if the flush fails, meaning the command buffer
126 // reader has shutdown.
[email protected]7d5b8d12011-01-14 23:43:15127 if (!FlushSync())
[email protected]96449d2c2009-11-25 00:01:32128 return;
129 }
[email protected]9310b262010-06-03 16:15:47130 // Insert a jump back to the beginning.
131 cmd::Jump::Set(&entries_[put_], 0);
[email protected]96449d2c2009-11-25 00:01:32132 put_ = 0;
133 }
[email protected]96449d2c2009-11-25 00:01:32134 while (AvailableEntries() < count) {
135 // Do not loop forever if the flush fails, meaning the command buffer reader
136 // has shutdown.
[email protected]7d5b8d12011-01-14 23:43:15137 if (!FlushSync())
[email protected]96449d2c2009-11-25 00:01:32138 return;
139 }
[email protected]7d5b8d12011-01-14 23:43:15140 // Force a flush if the buffer is getting half full, or even earlier if the
141 // reader is known to be idle.
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 }
[email protected]96449d2c2009-11-25 00:01:32148}
149
150CommandBufferEntry* CommandBufferHelper::GetSpace(uint32 entries) {
151 WaitForAvailableEntries(entries);
152 CommandBufferEntry* space = &entries_[put_];
153 put_ += entries;
[email protected]20407e92010-09-08 18:31:08154 GPU_DCHECK_LE(put_, usable_entry_count_);
[email protected]9310b262010-06-03 16:15:47155 if (put_ == usable_entry_count_) {
156 cmd::Jump::Set(&entries_[put_], 0);
[email protected]7e5bee52010-03-08 18:21:00157 put_ = 0;
158 }
[email protected]96449d2c2009-11-25 00:01:32159 return space;
160}
161
[email protected]f7a64ee2010-02-01 22:24:14162error::Error CommandBufferHelper::GetError() {
[email protected]c77ea362010-01-29 22:02:36163 CommandBuffer::State state = command_buffer_->GetState();
164 SynchronizeState(state);
[email protected]f7a64ee2010-02-01 22:24:14165 return static_cast<error::Error>(state.error);
[email protected]c77ea362010-01-29 22:02:36166}
167
168void CommandBufferHelper::SynchronizeState(CommandBuffer::State state) {
169 get_ = state.get_offset;
170 last_token_read_ = state.token;
[email protected]96449d2c2009-11-25 00:01:32171}
172
[email protected]a7a27ace2009-12-12 00:11:25173} // namespace gpu