OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2015 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. | |
4 | |
5 #include "gpu/command_buffer/service/path_manager.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "base/logging.h" | |
10 #include "gpu/command_buffer/common/gles2_cmd_utils.h" | |
11 #include "ui/gl/gl_bindings.h" | |
12 | |
13 namespace { | |
14 void CallDeletePaths(GLuint first_id, GLuint range) { | |
15 while (range > 0) { | |
16 GLsizei irange; | |
17 if (range > static_cast<GLuint>(std::numeric_limits<GLsizei>::max())) | |
18 irange = std::numeric_limits<GLsizei>::max(); | |
19 else | |
20 irange = static_cast<GLsizei>(range); | |
21 | |
22 glDeletePathsNV(first_id, irange); | |
23 range -= irange; | |
24 first_id += irange; | |
25 } | |
26 } | |
27 | |
28 } // anonymous namespace | |
29 | |
30 namespace gpu { | |
31 namespace gles2 { | |
32 | |
33 PathManager::PathManager() { | |
34 } | |
35 | |
36 PathManager::~PathManager() { | |
37 DCHECK(path_map_.empty()); | |
38 } | |
39 | |
40 void PathManager::Destroy(bool have_context) { | |
41 if (have_context) { | |
42 for (PathRangeMap::const_iterator it = path_map_.begin(); | |
43 it != path_map_.end(); ++it) | |
44 CallDeletePaths(FirstServiceId(it), RangeSize(it)); | |
45 } | |
46 path_map_.clear(); | |
47 } | |
48 | |
49 void PathManager::CreatePathRange(GLuint first_client_id, | |
50 GLuint last_client_id, | |
51 GLuint first_service_id) { | |
52 DCHECK(first_service_id > 0u); | |
53 DCHECK(first_client_id > 0u); | |
54 DCHECK(!HasPathsInRange(first_client_id, last_client_id)); | |
55 DCHECK(CheckConsistency()); | |
56 | |
57 PathRangeMap::iterator range = | |
58 GetContainingRange(path_map_, first_client_id - 1u); | |
59 | |
60 if (range != path_map_.end() && | |
61 LastServiceId(range) == first_service_id - 1u) { | |
62 DCHECK_EQ(LastClientId(range), first_client_id - 1u); | |
63 LastClientId(range) = last_client_id; | |
64 } else { | |
65 auto result = path_map_.insert( | |
66 std::make_pair(first_client_id, | |
67 PathRangeDescription(last_client_id, first_service_id))); | |
68 DCHECK(result.second); | |
69 range = result.first; | |
70 } | |
71 | |
72 PathRangeMap::iterator next_range = range; | |
73 ++next_range; | |
74 if (next_range != path_map_.end()) { | |
75 if (LastClientId(range) == FirstClientId(next_range) - 1u && | |
76 LastServiceId(range) == FirstServiceId(next_range) - 1u) { | |
77 LastClientId(range) = LastClientId(next_range); | |
78 path_map_.erase(next_range); | |
79 } | |
80 } | |
81 DCHECK(CheckConsistency()); | |
82 } | |
83 | |
84 bool PathManager::HasPathsInRange(GLuint first_client_id, | |
85 GLuint last_client_id) const { | |
86 PathRangeMap::const_iterator it = | |
87 GetContainingOrNextRange(path_map_, first_client_id); | |
88 if (it == path_map_.end()) | |
89 return false; | |
90 | |
91 return FirstClientId(it) <= last_client_id; | |
92 } | |
93 | |
94 bool PathManager::GetPath(GLuint client_id, GLuint* service_id) const { | |
95 PathRangeMap::const_iterator range = GetContainingRange(path_map_, client_id); | |
96 if (range == path_map_.end()) | |
97 return false; | |
98 | |
99 *service_id = FirstServiceId(range) + client_id - FirstClientId(range); | |
100 return true; | |
101 } | |
102 | |
103 void PathManager::RemovePaths(GLuint first_client_id, GLuint last_client_id) { | |
104 DCHECK(CheckConsistency()); | |
105 PathRangeMap::iterator it = | |
106 GetContainingOrNextRange(path_map_, first_client_id); | |
107 | |
108 while (it != path_map_.end() && FirstClientId(it) <= last_client_id) { | |
109 GLuint delete_first_client_id = | |
110 std::max(first_client_id, FirstClientId(it)); | |
111 GLuint delete_last_client_id = std::min(last_client_id, LastClientId(it)); | |
112 GLuint delete_first_service_id = | |
113 FirstServiceId(it) + delete_first_client_id - FirstClientId(it); | |
114 GLuint delete_range = delete_last_client_id - delete_first_client_id + 1u; | |
115 | |
116 CallDeletePaths(delete_first_service_id, delete_range); | |
117 | |
118 PathRangeMap::iterator current = it; | |
119 ++it; | |
120 | |
121 GLuint current_last_client_id = LastClientId(current); | |
122 | |
123 if (FirstClientId(current) < delete_first_client_id) | |
124 LastClientId(current) = delete_first_client_id - 1u; | |
125 else | |
126 path_map_.erase(current); | |
127 | |
128 if (current_last_client_id > delete_last_client_id) { | |
129 path_map_.insert(std::make_pair( | |
130 delete_last_client_id + 1u, | |
131 PathRangeDescription(current_last_client_id, | |
132 delete_first_service_id + delete_range))); | |
133 DCHECK(delete_last_client_id == last_client_id); | |
134 // This is necessarily the last range to check. Return early due to | |
135 // consistency. Iterator increment would skip the inserted range. The | |
136 // algorithm would work ok, but it looks weird. | |
137 DCHECK(CheckConsistency()); | |
138 return; | |
139 } | |
140 } | |
141 DCHECK(CheckConsistency()); | |
142 } | |
143 | |
144 template <typename MapType> | |
145 typename PathManager::IteratorSelector<MapType>::iterator | |
146 PathManager::GetContainingRange(MapType& path_map, GLuint client_id) { | |
147 typename IteratorSelector<MapType>::iterator it = | |
piman
2015/06/27 01:20:08
nit: feel free to use auto here.
| |
148 path_map.lower_bound(client_id); | |
149 if (it != path_map.end() && FirstClientId(it) == client_id) | |
150 return it; | |
151 if (it != path_map.begin()) { | |
152 --it; | |
153 if (LastClientId(it) >= client_id) | |
154 return it; | |
155 } | |
156 return path_map.end(); | |
157 } | |
158 | |
159 template <typename MapType> | |
160 typename PathManager::IteratorSelector<MapType>::iterator | |
161 PathManager::GetContainingOrNextRange(MapType& path_map, GLuint client_id) { | |
162 typename PathManager::IteratorSelector<MapType>::iterator it = | |
163 path_map.lower_bound(client_id); | |
164 if (it != path_map.end() && FirstClientId(it) == client_id) { | |
165 return it; | |
166 } | |
167 if (it != path_map.begin()) { | |
168 --it; | |
169 if (LastClientId(it) >= client_id) | |
170 return it; | |
171 ++it; | |
172 } | |
173 return it; | |
174 } | |
175 | |
176 bool PathManager::CheckConsistency() { | |
177 GLuint prev_first_client_id = 0u; | |
178 GLuint prev_last_client_id = 0u; | |
179 GLuint prev_first_service_id = 0u; | |
180 for (PathRangeMap::iterator range = path_map_.begin(); | |
181 range != path_map_.end(); ++range) { | |
182 // Code relies on ranges not starting at 0. Also, the above initialization | |
183 // is only | |
184 // correct then. | |
185 if (FirstClientId(range) == 0u || FirstServiceId(range) == 0u) | |
186 return false; | |
187 | |
188 // Each range is consistent. | |
189 if (FirstClientId(range) > LastClientId(range)) | |
190 return false; | |
191 | |
192 if (prev_first_client_id != 0u) { | |
193 // No overlapping ranges. (The iteration is sorted). | |
194 if (FirstClientId(range) <= prev_last_client_id) | |
195 return false; | |
196 | |
197 // No mergeable ranges. | |
198 bool is_mergeable_client = | |
199 FirstClientId(range) - 1u == prev_last_client_id; | |
200 bool is_mergeable_service = | |
201 FirstServiceId(range) - 1u == prev_first_service_id; | |
202 if (is_mergeable_client && is_mergeable_service) | |
203 return false; | |
204 } | |
205 prev_first_client_id = FirstClientId(range); | |
206 prev_last_client_id = LastClientId(range); | |
207 prev_first_service_id = FirstServiceId(range); | |
208 } | |
209 return true; | |
210 } | |
211 | |
212 } // namespace gles2 | |
213 } // namespace gpu | |
OLD | NEW |