| 122 | } |
| 123 | |
| 124 | ReadbackSpinManager::DrawSubmittedReturn ReadbackSpinManager::DrawSubmitted(u64 size) |
| 125 | { |
| 126 | DrawSubmittedReturn out = {}; |
| 127 | u32 idx = m_frames[m_current_frame].size(); |
| 128 | out.id = idx | m_current_frame << 28; |
| 129 | Event ev = {}; |
| 130 | ev.size = size; |
| 131 | m_frames[m_current_frame].push_back(ev); |
| 132 | |
| 133 | if (m_reference_frame != m_current_frame && |
| 134 | m_frames[m_reference_frame].size() > m_reference_frame_idx && |
| 135 | EventIsDraw(m_frames[m_reference_frame][m_reference_frame_idx])) |
| 136 | { |
| 137 | auto find_next_draw = [this](u32 frame) -> Event* { |
| 138 | auto next = std::find_if(m_frames[frame].begin() + m_reference_frame_idx + 1, |
| 139 | m_frames[frame].end(), |
| 140 | EventIsDraw); |
| 141 | bool found = next != m_frames[frame].end(); |
| 142 | if (!found) |
| 143 | { |
| 144 | u32 next_frame = NextFrameNo(frame, std::size(m_frames)); |
| 145 | next = std::find_if(m_frames[next_frame].begin(), m_frames[next_frame].end(), EventIsDraw); |
| 146 | found = next != m_frames[next_frame].end(); |
| 147 | } |
| 148 | return found ? &*next : nullptr; |
| 149 | }; |
| 150 | Event* cur_draw = &m_frames[m_reference_frame][m_reference_frame_idx]; |
| 151 | Event* next_draw = find_next_draw(m_reference_frame); |
| 152 | const bool is_one_frame_back = m_reference_frame == PrevFrameNo(m_current_frame, std::size(m_frames)); |
| 153 | if ((!next_draw || !IsCompleted(*cur_draw) || !IsCompleted(*next_draw)) && is_one_frame_back) |
| 154 | { |
| 155 | // Last frame's timing data hasn't arrived, try the same spot in the frame before |
| 156 | u32 two_back = PrevFrameNo(m_reference_frame, std::size(m_frames)); |
| 157 | if (m_frames[two_back].size() > m_reference_frame_idx && |
| 158 | EventIsDraw(m_frames[two_back][m_reference_frame_idx])) |
| 159 | { |
| 160 | cur_draw = &m_frames[two_back][m_reference_frame_idx]; |
| 161 | next_draw = find_next_draw(two_back); |
| 162 | } |
| 163 | } |
| 164 | if (next_draw && IsCompleted(*cur_draw) && IsCompleted(*next_draw) && m_spins_per_unit_time != 0) |
| 165 | { |
| 166 | u64 cur_size = cur_draw->size; |
| 167 | bool is_similar = cur_size / 2 <= size && size / 2 <= cur_size; |
| 168 | if (is_similar) // Only recommend spins if we're somewhat confident in what's going on |
| 169 | { |
| 170 | s32 current_draw_time = cur_draw->end - cur_draw->begin; |
| 171 | s32 gap = next_draw->begin - cur_draw->end; |
| 172 | // Give an extra bit of space for the draw to take a bit longer (we'll go with 1/8 longer) |
| 173 | s32 fill = gap - (current_draw_time >> 3); |
| 174 | if (fill > 0) |
| 175 | out.recommended_spin = static_cast<u32>(static_cast<double>(fill) * m_spins_per_unit_time); |
| 176 | } |
| 177 | } |
| 178 | |
| 179 | m_reference_frame_idx++; |
| 180 | } |
| 181 |
no test coverage detected