Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(76)

Side by Side Diff: gpu/command_buffer/client/program_info_manager.cc

Issue 893713002: Get rid of NonCachedProgramInfoManager. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 #include "gpu/command_buffer/client/program_info_manager.h" 5 #include "gpu/command_buffer/client/program_info_manager.h"
6 6
7 #include <string>
8
9 #include "base/compiler_specific.h"
10 #include "base/containers/hash_tables.h"
11 #include "base/synchronization/lock.h"
12 #include "gpu/command_buffer/client/gles2_implementation.h"
13 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
14
15 namespace gpu { 7 namespace gpu {
16 namespace gles2 { 8 namespace gles2 {
17 9
18 class NonCachedProgramInfoManager : public ProgramInfoManager { 10 ProgramInfoManager::ProgramInfoManager() {
19 public:
20 NonCachedProgramInfoManager();
21 ~NonCachedProgramInfoManager() override;
22
23 void CreateInfo(GLuint program) override;
24
25 void DeleteInfo(GLuint program) override;
26
27 bool GetProgramiv(GLES2Implementation* gl,
28 GLuint program,
29 GLenum pname,
30 GLint* params) override;
31
32 GLint GetAttribLocation(GLES2Implementation* gl,
33 GLuint program,
34 const char* name) override;
35
36 GLint GetUniformLocation(GLES2Implementation* gl,
37 GLuint program,
38 const char* name) override;
39
40 GLint GetFragDataLocation(GLES2Implementation* gl,
41 GLuint program,
42 const char* name) override;
43
44 bool GetActiveAttrib(GLES2Implementation* gl,
45 GLuint program,
46 GLuint index,
47 GLsizei bufsize,
48 GLsizei* length,
49 GLint* size,
50 GLenum* type,
51 char* name) override;
52
53 bool GetActiveUniform(GLES2Implementation* gl,
54 GLuint program,
55 GLuint index,
56 GLsizei bufsize,
57 GLsizei* length,
58 GLint* size,
59 GLenum* type,
60 char* name) override;
61 };
62
63 NonCachedProgramInfoManager::NonCachedProgramInfoManager() {
64 } 11 }
65 12
66 NonCachedProgramInfoManager::~NonCachedProgramInfoManager() { 13 ProgramInfoManager::~ProgramInfoManager() {
67 } 14 }
68 15
69 void NonCachedProgramInfoManager::CreateInfo(GLuint /* program */) { 16 ProgramInfoManager::Program* ProgramInfoManager::GetProgramInfo(
70 } 17 GLES2Implementation* gl, GLuint program) {
71
72 void NonCachedProgramInfoManager::DeleteInfo(GLuint /* program */) {
73 }
74
75 bool NonCachedProgramInfoManager::GetProgramiv(
76 GLES2Implementation* /* gl */,
77 GLuint /* program */,
78 GLenum /* pname */,
79 GLint* /* params */) {
80 return false;
81 }
82
83 GLint NonCachedProgramInfoManager::GetAttribLocation(
84 GLES2Implementation* gl, GLuint program, const char* name) {
85 return gl->GetAttribLocationHelper(program, name);
86 }
87
88 GLint NonCachedProgramInfoManager::GetUniformLocation(
89 GLES2Implementation* gl, GLuint program, const char* name) {
90 return gl->GetUniformLocationHelper(program, name);
91 }
92
93 GLint NonCachedProgramInfoManager::GetFragDataLocation(
94 GLES2Implementation* gl, GLuint program, const char* name) {
95 return gl->GetFragDataLocationHelper(program, name);
96 }
97
98 bool NonCachedProgramInfoManager::GetActiveAttrib(
99 GLES2Implementation* gl,
100 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length,
101 GLint* size, GLenum* type, char* name) {
102 return gl->GetActiveAttribHelper(
103 program, index, bufsize, length, size, type, name);
104 }
105
106 bool NonCachedProgramInfoManager::GetActiveUniform(
107 GLES2Implementation* gl,
108 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length,
109 GLint* size, GLenum* type, char* name) {
110 return gl->GetActiveUniformHelper(
111 program, index, bufsize, length, size, type, name);
112 }
113
114 class CachedProgramInfoManager : public ProgramInfoManager {
115 public:
116 CachedProgramInfoManager();
117 ~CachedProgramInfoManager() override;
118
119 void CreateInfo(GLuint program) override;
120
121 void DeleteInfo(GLuint program) override;
122
123 bool GetProgramiv(GLES2Implementation* gl,
124 GLuint program,
125 GLenum pname,
126 GLint* params) override;
127
128 GLint GetAttribLocation(GLES2Implementation* gl,
129 GLuint program,
130 const char* name) override;
131
132 GLint GetUniformLocation(GLES2Implementation* gl,
133 GLuint program,
134 const char* name) override;
135
136 GLint GetFragDataLocation(GLES2Implementation* gl,
137 GLuint program,
138 const char* name) override;
139
140 bool GetActiveAttrib(GLES2Implementation* gl,
141 GLuint program,
142 GLuint index,
143 GLsizei bufsize,
144 GLsizei* length,
145 GLint* size,
146 GLenum* type,
147 char* name) override;
148
149 bool GetActiveUniform(GLES2Implementation* gl,
150 GLuint program,
151 GLuint index,
152 GLsizei bufsize,
153 GLsizei* length,
154 GLint* size,
155 GLenum* type,
156 char* name) override;
157
158 private:
159 class Program {
160 public:
161 struct UniformInfo {
162 UniformInfo(GLsizei _size, GLenum _type, const std::string& _name);
163
164 GLsizei size;
165 GLenum type;
166 bool is_array;
167 std::string name;
168 std::vector<GLint> element_locations;
169 };
170 struct VertexAttrib {
171 VertexAttrib(GLsizei _size, GLenum _type, const std::string& _name,
172 GLint _location)
173 : size(_size),
174 type(_type),
175 location(_location),
176 name(_name) {
177 }
178 GLsizei size;
179 GLenum type;
180 GLint location;
181 std::string name;
182 };
183
184 typedef std::vector<UniformInfo> UniformInfoVector;
185 typedef std::vector<VertexAttrib> AttribInfoVector;
186
187 Program();
188
189 const AttribInfoVector& GetAttribInfos() const {
190 return attrib_infos_;
191 }
192
193 const VertexAttrib* GetAttribInfo(GLint index) const {
194 return (static_cast<size_t>(index) < attrib_infos_.size()) ?
195 &attrib_infos_[index] : NULL;
196 }
197
198 GLint GetAttribLocation(const std::string& name) const;
199
200 const UniformInfo* GetUniformInfo(GLint index) const {
201 return (static_cast<size_t>(index) < uniform_infos_.size()) ?
202 &uniform_infos_[index] : NULL;
203 }
204
205 // Gets the location of a uniform by name.
206 GLint GetUniformLocation(const std::string& name) const;
207
208 GLint GetFragDataLocation(const std::string& name) const;
209 void CacheFragDataLocation(const std::string& name, GLint loc);
210
211 bool GetProgramiv(GLenum pname, GLint* params);
212
213 // Updates the program info after a successful link.
214 void Update(GLES2Implementation* gl,
215 GLuint program,
216 const std::vector<int8>& result);
217
218 bool cached() const { return cached_; }
219
220 private:
221 bool cached_;
222
223 GLsizei max_attrib_name_length_;
224
225 // Attrib by index.
226 AttribInfoVector attrib_infos_;
227
228 GLsizei max_uniform_name_length_;
229
230 // Uniform info by index.
231 UniformInfoVector uniform_infos_;
232
233 base::hash_map<std::string, GLint> frag_data_locations_;
234
235 // This is true if glLinkProgram was successful last time it was called.
236 bool link_status_;
237 };
238
239 Program* GetProgramInfo(GLES2Implementation* gl, GLuint program);
240
241 typedef base::hash_map<GLuint, Program> ProgramInfoMap;
242
243 ProgramInfoMap program_infos_;
244
245 mutable base::Lock lock_;
246 };
247
248 CachedProgramInfoManager::Program::UniformInfo::UniformInfo(
249 GLsizei _size, GLenum _type, const std::string& _name)
250 : size(_size),
251 type(_type),
252 name(_name) {
253 is_array = (!name.empty() && name[name.size() - 1] == ']');
254 DCHECK(!(size > 1 && !is_array));
255 }
256
257 CachedProgramInfoManager::Program::Program()
258 : cached_(false),
259 max_attrib_name_length_(0),
260 max_uniform_name_length_(0),
261 link_status_(false) {
262 }
263
264 // TODO(gman): Add a faster lookup.
265 GLint CachedProgramInfoManager::Program::GetAttribLocation(
266 const std::string& name) const {
267 for (GLuint ii = 0; ii < attrib_infos_.size(); ++ii) {
268 const VertexAttrib& info = attrib_infos_[ii];
269 if (info.name == name) {
270 return info.location;
271 }
272 }
273 return -1;
274 }
275
276 GLint CachedProgramInfoManager::Program::GetUniformLocation(
277 const std::string& name) const {
278 bool getting_array_location = false;
279 size_t open_pos = std::string::npos;
280 int index = 0;
281 if (!GLES2Util::ParseUniformName(
282 name, &open_pos, &index, &getting_array_location)) {
283 return -1;
284 }
285 for (GLuint ii = 0; ii < uniform_infos_.size(); ++ii) {
286 const UniformInfo& info = uniform_infos_[ii];
287 if (info.name == name ||
288 (info.is_array &&
289 info.name.compare(0, info.name.size() - 3, name) == 0)) {
290 return info.element_locations[0];
291 } else if (getting_array_location && info.is_array) {
292 // Look for an array specification.
293 size_t open_pos_2 = info.name.find_last_of('[');
294 if (open_pos_2 == open_pos &&
295 name.compare(0, open_pos, info.name, 0, open_pos) == 0) {
296 if (index >= 0 && index < info.size) {
297 return info.element_locations[index];
298 }
299 }
300 }
301 }
302 return -1;
303 }
304
305 GLint CachedProgramInfoManager::Program::GetFragDataLocation(
306 const std::string& name) const {
307 base::hash_map<std::string, GLint>::const_iterator iter =
308 frag_data_locations_.find(name);
309 if (iter == frag_data_locations_.end())
310 return -1;
311 return iter->second;
312 }
313
314 void CachedProgramInfoManager::Program::CacheFragDataLocation(
315 const std::string& name, GLint loc) {
316 frag_data_locations_[name] = loc;
317 }
318
319 bool CachedProgramInfoManager::Program::GetProgramiv(
320 GLenum pname, GLint* params) {
321 switch (pname) {
322 case GL_LINK_STATUS:
323 *params = link_status_;
324 return true;
325 case GL_ACTIVE_ATTRIBUTES:
326 *params = attrib_infos_.size();
327 return true;
328 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
329 *params = max_attrib_name_length_;
330 return true;
331 case GL_ACTIVE_UNIFORMS:
332 *params = uniform_infos_.size();
333 return true;
334 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
335 *params = max_uniform_name_length_;
336 return true;
337 default:
338 break;
339 }
340 return false;
341 }
342
343 template<typename T> static T LocalGetAs(
344 const std::vector<int8>& data, uint32 offset, size_t size) {
345 const int8* p = &data[0] + offset;
346 if (offset + size > data.size()) {
347 NOTREACHED();
348 return NULL;
349 }
350 return static_cast<T>(static_cast<const void*>(p));
351 }
352
353 void CachedProgramInfoManager::Program::Update(
354 GLES2Implementation* gl,
355 GLuint program,
356 const std::vector<int8>& result) {
357 if (cached_) {
358 return;
359 }
360 if (result.empty()) {
361 // This should only happen on a lost context.
362 return;
363 }
364 DCHECK_GE(result.size(), sizeof(ProgramInfoHeader));
365 const ProgramInfoHeader* header = LocalGetAs<const ProgramInfoHeader*>(
366 result, 0, sizeof(header));
367 link_status_ = header->link_status != 0;
368 if (!link_status_) {
369 return;
370 }
371 attrib_infos_.clear();
372 uniform_infos_.clear();
373 frag_data_locations_.clear();
374 max_attrib_name_length_ = 0;
375 max_uniform_name_length_ = 0;
376 const ProgramInput* inputs = LocalGetAs<const ProgramInput*>(
377 result, sizeof(*header),
378 sizeof(ProgramInput) * (header->num_attribs + header->num_uniforms));
379 const ProgramInput* input = inputs;
380 for (uint32 ii = 0; ii < header->num_attribs; ++ii) {
381 const int32* location = LocalGetAs<const int32*>(
382 result, input->location_offset, sizeof(int32));
383 const char* name_buf = LocalGetAs<const char*>(
384 result, input->name_offset, input->name_length);
385 std::string name(name_buf, input->name_length);
386 attrib_infos_.push_back(
387 VertexAttrib(input->size, input->type, name, *location));
388 max_attrib_name_length_ = std::max(
389 static_cast<GLsizei>(name.size() + 1), max_attrib_name_length_);
390 ++input;
391 }
392 for (uint32 ii = 0; ii < header->num_uniforms; ++ii) {
393 const int32* locations = LocalGetAs<const int32*>(
394 result, input->location_offset, sizeof(int32) * input->size);
395 const char* name_buf = LocalGetAs<const char*>(
396 result, input->name_offset, input->name_length);
397 std::string name(name_buf, input->name_length);
398 UniformInfo info(input->size, input->type, name);
399 max_uniform_name_length_ = std::max(
400 static_cast<GLsizei>(name.size() + 1), max_uniform_name_length_);
401 for (int32 jj = 0; jj < input->size; ++jj) {
402 info.element_locations.push_back(locations[jj]);
403 }
404 uniform_infos_.push_back(info);
405 ++input;
406 }
407 DCHECK_EQ(header->num_attribs + header->num_uniforms,
408 static_cast<uint32>(input - inputs));
409 cached_ = true;
410 }
411
412 CachedProgramInfoManager::CachedProgramInfoManager() {
413 }
414
415 CachedProgramInfoManager::~CachedProgramInfoManager() {
416
417 }
418
419 CachedProgramInfoManager::Program*
420 CachedProgramInfoManager::GetProgramInfo(
421 GLES2Implementation* gl, GLuint program) {
422 lock_.AssertAcquired(); 18 lock_.AssertAcquired();
423 ProgramInfoMap::iterator it = program_infos_.find(program); 19 ProgramInfoMap::iterator it = program_infos_.find(program);
424 if (it == program_infos_.end()) { 20 if (it == program_infos_.end()) {
425 return NULL; 21 return NULL;
426 } 22 }
427 Program* info = &it->second; 23 Program* info = &it->second;
428 if (info->cached()) 24 if (info->cached())
429 return info; 25 return info;
430 std::vector<int8> result; 26 std::vector<int8> result;
431 { 27 {
432 base::AutoUnlock unlock(lock_); 28 base::AutoUnlock unlock(lock_);
433 // lock_ can't be held across IPC call or else it may deadlock in pepper. 29 // lock_ can't be held across IPC call or else it may deadlock in pepper.
434 // http://crbug.com/418651 30 // http://crbug.com/418651
435 gl->GetProgramInfoCHROMIUMHelper(program, &result); 31 gl->GetProgramInfoCHROMIUMHelper(program, &result);
436 } 32 }
437 33
438 it = program_infos_.find(program); 34 it = program_infos_.find(program);
439 if (it == program_infos_.end()) { 35 if (it == program_infos_.end()) {
440 return NULL; 36 return NULL;
441 } 37 }
442 info = &it->second; 38 info = &it->second;
443 info->Update(gl, program, result); 39 info->Update(gl, program, result);
444 return info; 40 return info;
445 } 41 }
446 42
447 void CachedProgramInfoManager::CreateInfo(GLuint program) { 43 void ProgramInfoManager::CreateInfo(GLuint program) {
448 base::AutoLock auto_lock(lock_); 44 base::AutoLock auto_lock(lock_);
449 program_infos_.erase(program); 45 program_infos_.erase(program);
450 std::pair<ProgramInfoMap::iterator, bool> result = 46 std::pair<ProgramInfoMap::iterator, bool> result =
451 program_infos_.insert(std::make_pair(program, Program())); 47 program_infos_.insert(std::make_pair(program, Program()));
452 48
453 DCHECK(result.second); 49 DCHECK(result.second);
454 } 50 }
455 51
456 void CachedProgramInfoManager::DeleteInfo(GLuint program) { 52 void ProgramInfoManager::DeleteInfo(GLuint program) {
457 base::AutoLock auto_lock(lock_); 53 base::AutoLock auto_lock(lock_);
458 program_infos_.erase(program); 54 program_infos_.erase(program);
459 } 55 }
460 56
461 bool CachedProgramInfoManager::GetProgramiv( 57 bool ProgramInfoManager::GetProgramiv(
462 GLES2Implementation* gl, GLuint program, GLenum pname, GLint* params) { 58 GLES2Implementation* gl, GLuint program, GLenum pname, GLint* params) {
463 base::AutoLock auto_lock(lock_); 59 base::AutoLock auto_lock(lock_);
464 Program* info = GetProgramInfo(gl, program); 60 Program* info = GetProgramInfo(gl, program);
465 if (!info) { 61 if (!info) {
466 return false; 62 return false;
467 } 63 }
468 return info->GetProgramiv(pname, params); 64 return info->GetProgramiv(pname, params);
469 } 65 }
470 66
471 GLint CachedProgramInfoManager::GetAttribLocation( 67 GLint ProgramInfoManager::GetAttribLocation(
472 GLES2Implementation* gl, GLuint program, const char* name) { 68 GLES2Implementation* gl, GLuint program, const char* name) {
473 { 69 {
474 base::AutoLock auto_lock(lock_); 70 base::AutoLock auto_lock(lock_);
475 Program* info = GetProgramInfo(gl, program); 71 Program* info = GetProgramInfo(gl, program);
476 if (info) { 72 if (info) {
477 return info->GetAttribLocation(name); 73 return info->GetAttribLocation(name);
478 } 74 }
479 } 75 }
480 return gl->GetAttribLocationHelper(program, name); 76 return gl->GetAttribLocationHelper(program, name);
481 } 77 }
482 78
483 GLint CachedProgramInfoManager::GetUniformLocation( 79 GLint ProgramInfoManager::GetUniformLocation(
484 GLES2Implementation* gl, GLuint program, const char* name) { 80 GLES2Implementation* gl, GLuint program, const char* name) {
485 { 81 {
486 base::AutoLock auto_lock(lock_); 82 base::AutoLock auto_lock(lock_);
487 Program* info = GetProgramInfo(gl, program); 83 Program* info = GetProgramInfo(gl, program);
488 if (info) { 84 if (info) {
489 return info->GetUniformLocation(name); 85 return info->GetUniformLocation(name);
490 } 86 }
491 } 87 }
492 return gl->GetUniformLocationHelper(program, name); 88 return gl->GetUniformLocationHelper(program, name);
493 } 89 }
494 90
495 GLint CachedProgramInfoManager::GetFragDataLocation( 91 GLint ProgramInfoManager::GetFragDataLocation(
496 GLES2Implementation* gl, GLuint program, const char* name) { 92 GLES2Implementation* gl, GLuint program, const char* name) {
497 // TODO(zmo): make FragData locations part of the ProgramInfo that are 93 // TODO(zmo): make FragData locations part of the ProgramInfo that are
498 // fetched altogether from the service side. See crbug.com/452104. 94 // fetched altogether from the service side. See crbug.com/452104.
499 { 95 {
500 base::AutoLock auto_lock(lock_); 96 base::AutoLock auto_lock(lock_);
501 Program* info = GetProgramInfo(gl, program); 97 Program* info = GetProgramInfo(gl, program);
502 if (info) { 98 if (info) {
503 GLint possible_loc = info->GetFragDataLocation(name); 99 GLint possible_loc = info->GetFragDataLocation(name);
504 if (possible_loc != -1) 100 if (possible_loc != -1)
505 return possible_loc; 101 return possible_loc;
506 } 102 }
507 } 103 }
508 GLint loc = gl->GetFragDataLocationHelper(program, name); 104 GLint loc = gl->GetFragDataLocationHelper(program, name);
509 if (loc != -1) { 105 if (loc != -1) {
510 base::AutoLock auto_lock(lock_); 106 base::AutoLock auto_lock(lock_);
511 Program* info = GetProgramInfo(gl, program); 107 Program* info = GetProgramInfo(gl, program);
512 if (info) { 108 if (info) {
513 info->CacheFragDataLocation(name, loc); 109 info->CacheFragDataLocation(name, loc);
514 } 110 }
515 } 111 }
516 return loc; 112 return loc;
517 } 113 }
518 114
519 bool CachedProgramInfoManager::GetActiveAttrib( 115 bool ProgramInfoManager::GetActiveAttrib(
520 GLES2Implementation* gl, 116 GLES2Implementation* gl,
521 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, 117 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length,
522 GLint* size, GLenum* type, char* name) { 118 GLint* size, GLenum* type, char* name) {
523 { 119 {
524 base::AutoLock auto_lock(lock_); 120 base::AutoLock auto_lock(lock_);
525 Program* info = GetProgramInfo(gl, program); 121 Program* info = GetProgramInfo(gl, program);
526 if (info) { 122 if (info) {
527 const Program::VertexAttrib* attrib_info = info->GetAttribInfo(index); 123 const Program::VertexAttrib* attrib_info = info->GetAttribInfo(index);
528 if (attrib_info) { 124 if (attrib_info) {
529 if (size) { 125 if (size) {
(...skipping 15 matching lines...) Expand all
545 } 141 }
546 } 142 }
547 return true; 143 return true;
548 } 144 }
549 } 145 }
550 } 146 }
551 return gl->GetActiveAttribHelper( 147 return gl->GetActiveAttribHelper(
552 program, index, bufsize, length, size, type, name); 148 program, index, bufsize, length, size, type, name);
553 } 149 }
554 150
555 bool CachedProgramInfoManager::GetActiveUniform( 151 bool ProgramInfoManager::GetActiveUniform(
556 GLES2Implementation* gl, 152 GLES2Implementation* gl,
557 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, 153 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length,
558 GLint* size, GLenum* type, char* name) { 154 GLint* size, GLenum* type, char* name) {
559 { 155 {
560 base::AutoLock auto_lock(lock_); 156 base::AutoLock auto_lock(lock_);
561 Program* info = GetProgramInfo(gl, program); 157 Program* info = GetProgramInfo(gl, program);
562 if (info) { 158 if (info) {
563 const Program::UniformInfo* uniform_info = info->GetUniformInfo(index); 159 const Program::UniformInfo* uniform_info = info->GetUniformInfo(index);
564 if (uniform_info) { 160 if (uniform_info) {
565 if (size) { 161 if (size) {
(...skipping 15 matching lines...) Expand all
581 } 177 }
582 } 178 }
583 return true; 179 return true;
584 } 180 }
585 } 181 }
586 } 182 }
587 return gl->GetActiveUniformHelper( 183 return gl->GetActiveUniformHelper(
588 program, index, bufsize, length, size, type, name); 184 program, index, bufsize, length, size, type, name);
589 } 185 }
590 186
591 ProgramInfoManager::ProgramInfoManager() {
592 }
593
594 ProgramInfoManager::~ProgramInfoManager() {
595 }
596
597 ProgramInfoManager* ProgramInfoManager::Create(
598 bool shared_resources_across_processes) {
599 if (shared_resources_across_processes) {
600 return new NonCachedProgramInfoManager();
601 } else {
602 return new CachedProgramInfoManager();
603 }
604 }
605
606 } // namespace gles2 187 } // namespace gles2
607 } // namespace gpu 188 } // namespace gpu
608 189
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698