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

Side by Side Diff: cc/resources/resource_provider.cc

Issue 22529002: [cc] Allow resources and ui resources to specify wrap mode (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix typo and add asserts Created 7 years, 4 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 2012 The Chromium Authors. All rights reserved. 1 // Copyright 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 "cc/resources/resource_provider.h" 5 #include "cc/resources/resource_provider.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <limits> 8 #include <limits>
9 9
10 #include "base/containers/hash_tables.h" 10 #include "base/containers/hash_tables.h"
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
46 } 46 }
47 47
48 bool IsTextureFormatSupportedForStorage(GLenum format) { 48 bool IsTextureFormatSupportedForStorage(GLenum format) {
49 return (format == GL_RGBA || format == GL_BGRA_EXT); 49 return (format == GL_RGBA || format == GL_BGRA_EXT);
50 } 50 }
51 51
52 unsigned CreateTextureId(WebGraphicsContext3D* context3d) { 52 unsigned CreateTextureId(WebGraphicsContext3D* context3d) {
53 unsigned texture_id = 0; 53 unsigned texture_id = 0;
54 GLC(context3d, texture_id = context3d->createTexture()); 54 GLC(context3d, texture_id = context3d->createTexture());
55 GLC(context3d, context3d->bindTexture(GL_TEXTURE_2D, texture_id)); 55 GLC(context3d, context3d->bindTexture(GL_TEXTURE_2D, texture_id));
56 GLC(context3d, context3d->texParameteri( 56 GLC(context3d, context3d->texParameteri(
enne (OOO) 2013/08/07 20:57:52 This is just a drive-by nit, but it's a little wei
ccameron 2013/08/31 00:37:58 Done.
57 GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); 57 GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
58 GLC(context3d, context3d->texParameteri( 58 GLC(context3d, context3d->texParameteri(
59 GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); 59 GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
60 GLC(context3d, context3d->texParameteri(
61 GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
62 GLC(context3d, context3d->texParameteri(
63 GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
64 return texture_id; 60 return texture_id;
65 } 61 }
66 62
67 } // namespace 63 } // namespace
68 64
69 ResourceProvider::Resource::Resource() 65 ResourceProvider::Resource::Resource()
70 : gl_id(0), 66 : gl_id(0),
71 gl_pixel_buffer_id(0), 67 gl_pixel_buffer_id(0),
72 gl_upload_query_id(0), 68 gl_upload_query_id(0),
73 pixels(NULL), 69 pixels(NULL),
74 pixel_buffer(NULL), 70 pixel_buffer(NULL),
75 lock_for_read_count(0), 71 lock_for_read_count(0),
76 locked_for_write(false), 72 locked_for_write(false),
77 external(false), 73 external(false),
78 exported(false), 74 exported(false),
79 marked_for_deletion(false), 75 marked_for_deletion(false),
80 pending_set_pixels(false), 76 pending_set_pixels(false),
81 set_pixels_completion_forced(false), 77 set_pixels_completion_forced(false),
82 allocated(false), 78 allocated(false),
83 enable_read_lock_fences(false), 79 enable_read_lock_fences(false),
84 read_lock_fence(NULL), 80 read_lock_fence(NULL),
85 size(), 81 size(),
86 format(0), 82 format(0),
87 filter(0), 83 filter(0),
88 image_id(0), 84 image_id(0),
89 texture_pool(0), 85 texture_pool(0),
86 wrap_mode(0),
90 hint(TextureUsageAny), 87 hint(TextureUsageAny),
91 type(static_cast<ResourceType>(0)) {} 88 type(static_cast<ResourceType>(0)) {}
92 89
93 ResourceProvider::Resource::~Resource() {} 90 ResourceProvider::Resource::~Resource() {}
94 91
95 ResourceProvider::Resource::Resource( 92 ResourceProvider::Resource::Resource(
96 unsigned texture_id, 93 unsigned texture_id,
97 gfx::Size size, 94 gfx::Size size,
98 GLenum format, 95 GLenum format,
99 GLenum filter, 96 GLenum filter,
100 GLenum texture_pool, 97 GLenum texture_pool,
98 GLint wrap_mode,
101 TextureUsageHint hint) 99 TextureUsageHint hint)
102 : gl_id(texture_id), 100 : gl_id(texture_id),
103 gl_pixel_buffer_id(0), 101 gl_pixel_buffer_id(0),
104 gl_upload_query_id(0), 102 gl_upload_query_id(0),
105 pixels(NULL), 103 pixels(NULL),
106 pixel_buffer(NULL), 104 pixel_buffer(NULL),
107 lock_for_read_count(0), 105 lock_for_read_count(0),
108 locked_for_write(false), 106 locked_for_write(false),
109 external(false), 107 external(false),
110 exported(false), 108 exported(false),
111 marked_for_deletion(false), 109 marked_for_deletion(false),
112 pending_set_pixels(false), 110 pending_set_pixels(false),
113 set_pixels_completion_forced(false), 111 set_pixels_completion_forced(false),
114 allocated(false), 112 allocated(false),
115 enable_read_lock_fences(false), 113 enable_read_lock_fences(false),
116 read_lock_fence(NULL), 114 read_lock_fence(NULL),
117 size(size), 115 size(size),
118 format(format), 116 format(format),
119 filter(filter), 117 filter(filter),
120 image_id(0), 118 image_id(0),
121 texture_pool(texture_pool), 119 texture_pool(texture_pool),
120 wrap_mode(wrap_mode),
122 hint(hint), 121 hint(hint),
123 type(GLTexture) {} 122 type(GLTexture) {
123 DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
124 }
124 125
125 ResourceProvider::Resource::Resource( 126 ResourceProvider::Resource::Resource(
126 uint8_t* pixels, gfx::Size size, GLenum format, GLenum filter) 127 uint8_t* pixels,
128 gfx::Size size,
129 GLenum format,
130 GLenum filter,
131 GLint wrap_mode)
127 : gl_id(0), 132 : gl_id(0),
128 gl_pixel_buffer_id(0), 133 gl_pixel_buffer_id(0),
129 gl_upload_query_id(0), 134 gl_upload_query_id(0),
130 pixels(pixels), 135 pixels(pixels),
131 pixel_buffer(NULL), 136 pixel_buffer(NULL),
132 lock_for_read_count(0), 137 lock_for_read_count(0),
133 locked_for_write(false), 138 locked_for_write(false),
134 external(false), 139 external(false),
135 exported(false), 140 exported(false),
136 marked_for_deletion(false), 141 marked_for_deletion(false),
137 pending_set_pixels(false), 142 pending_set_pixels(false),
138 set_pixels_completion_forced(false), 143 set_pixels_completion_forced(false),
139 allocated(false), 144 allocated(false),
140 enable_read_lock_fences(false), 145 enable_read_lock_fences(false),
141 read_lock_fence(NULL), 146 read_lock_fence(NULL),
142 size(size), 147 size(size),
143 format(format), 148 format(format),
144 filter(filter), 149 filter(filter),
145 image_id(0), 150 image_id(0),
146 texture_pool(0), 151 texture_pool(0),
152 wrap_mode(wrap_mode),
147 hint(TextureUsageAny), 153 hint(TextureUsageAny),
148 type(Bitmap) {} 154 type(Bitmap) {
155 DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
156 }
149 157
150 ResourceProvider::Child::Child() {} 158 ResourceProvider::Child::Child() {}
151 159
152 ResourceProvider::Child::~Child() {} 160 ResourceProvider::Child::~Child() {}
153 161
154 scoped_ptr<ResourceProvider> ResourceProvider::Create( 162 scoped_ptr<ResourceProvider> ResourceProvider::Create(
155 OutputSurface* output_surface, 163 OutputSurface* output_surface,
156 int highp_threshold_min) { 164 int highp_threshold_min) {
157 scoped_ptr<ResourceProvider> resource_provider( 165 scoped_ptr<ResourceProvider> resource_provider(
158 new ResourceProvider(output_surface, highp_threshold_min)); 166 new ResourceProvider(output_surface, highp_threshold_min));
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
190 CHECK(it != resources_.end()); 198 CHECK(it != resources_.end());
191 Resource* resource = &it->second; 199 Resource* resource = &it->second;
192 return !!resource->lock_for_read_count || resource->exported; 200 return !!resource->lock_for_read_count || resource->exported;
193 } 201 }
194 202
195 ResourceProvider::ResourceId ResourceProvider::CreateResource( 203 ResourceProvider::ResourceId ResourceProvider::CreateResource(
196 gfx::Size size, GLenum format, TextureUsageHint hint) { 204 gfx::Size size, GLenum format, TextureUsageHint hint) {
197 DCHECK(!size.IsEmpty()); 205 DCHECK(!size.IsEmpty());
198 switch (default_resource_type_) { 206 switch (default_resource_type_) {
199 case GLTexture: 207 case GLTexture:
200 return CreateGLTexture( 208 return CreateGLTexture(size, format, GL_TEXTURE_POOL_UNMANAGED_CHROMIUM,
201 size, format, GL_TEXTURE_POOL_UNMANAGED_CHROMIUM, hint); 209 GL_CLAMP_TO_EDGE, hint);
202 case Bitmap: 210 case Bitmap:
203 DCHECK(format == GL_RGBA); 211 DCHECK(format == GL_RGBA);
204 return CreateBitmap(size); 212 return CreateBitmap(size);
205 case InvalidType: 213 case InvalidType:
206 break; 214 break;
207 } 215 }
208 216
209 LOG(FATAL) << "Invalid default resource type."; 217 LOG(FATAL) << "Invalid default resource type.";
210 return 0; 218 return 0;
211 } 219 }
212 220
213 ResourceProvider::ResourceId ResourceProvider::CreateManagedResource( 221 ResourceProvider::ResourceId ResourceProvider::CreateManagedResource(
214 gfx::Size size, GLenum format, TextureUsageHint hint) { 222 gfx::Size size, GLenum format, TextureUsageHint hint) {
215 DCHECK(!size.IsEmpty()); 223 DCHECK(!size.IsEmpty());
216 switch (default_resource_type_) { 224 switch (default_resource_type_) {
217 case GLTexture: 225 case GLTexture:
218 return CreateGLTexture( 226 return CreateGLTexture(size, format, GL_TEXTURE_POOL_MANAGED_CHROMIUM,
219 size, format, GL_TEXTURE_POOL_MANAGED_CHROMIUM, hint); 227 GL_CLAMP_TO_EDGE, hint);
220 case Bitmap: 228 case Bitmap:
221 DCHECK(format == GL_RGBA); 229 DCHECK(format == GL_RGBA);
222 return CreateBitmap(size); 230 return CreateBitmap(size);
223 case InvalidType: 231 case InvalidType:
224 break; 232 break;
225 } 233 }
226 234
227 LOG(FATAL) << "Invalid default resource type."; 235 LOG(FATAL) << "Invalid default resource type.";
228 return 0; 236 return 0;
229 } 237 }
230 238
231 ResourceProvider::ResourceId ResourceProvider::CreateGLTexture( 239 ResourceProvider::ResourceId ResourceProvider::CreateGLTexture(
232 gfx::Size size, GLenum format, GLenum texture_pool, TextureUsageHint hint) { 240 gfx::Size size,
241 GLenum format,
242 GLenum texture_pool,
243 GLint wrap_mode,
244 TextureUsageHint hint) {
233 DCHECK_LE(size.width(), max_texture_size_); 245 DCHECK_LE(size.width(), max_texture_size_);
234 DCHECK_LE(size.height(), max_texture_size_); 246 DCHECK_LE(size.height(), max_texture_size_);
235 DCHECK(thread_checker_.CalledOnValidThread()); 247 DCHECK(thread_checker_.CalledOnValidThread());
236 248
237 ResourceId id = next_id_++; 249 ResourceId id = next_id_++;
238 Resource resource(0, size, format, GL_LINEAR, texture_pool, hint); 250 Resource resource(0, size, format, GL_LINEAR, texture_pool, wrap_mode, hint);
239 resource.allocated = false; 251 resource.allocated = false;
240 resources_[id] = resource; 252 resources_[id] = resource;
241 return id; 253 return id;
242 } 254 }
243 255
244 ResourceProvider::ResourceId ResourceProvider::CreateBitmap(gfx::Size size) { 256 ResourceProvider::ResourceId ResourceProvider::CreateBitmap(gfx::Size size) {
245 DCHECK(thread_checker_.CalledOnValidThread()); 257 DCHECK(thread_checker_.CalledOnValidThread());
246 258
247 uint8_t* pixels = new uint8_t[4 * size.GetArea()]; 259 uint8_t* pixels = new uint8_t[4 * size.GetArea()];
248 260
249 ResourceId id = next_id_++; 261 ResourceId id = next_id_++;
250 Resource resource(pixels, size, GL_RGBA, GL_LINEAR); 262 Resource resource(pixels, size, GL_RGBA, GL_LINEAR, GL_CLAMP_TO_EDGE);
251 resource.allocated = true; 263 resource.allocated = true;
252 resources_[id] = resource; 264 resources_[id] = resource;
253 return id; 265 return id;
254 } 266 }
255 267
256 ResourceProvider::ResourceId 268 ResourceProvider::ResourceId
257 ResourceProvider::CreateResourceFromExternalTexture( 269 ResourceProvider::CreateResourceFromExternalTexture(
258 unsigned texture_target, 270 unsigned texture_target,
259 unsigned texture_id) { 271 unsigned texture_id) {
260 DCHECK(thread_checker_.CalledOnValidThread()); 272 DCHECK(thread_checker_.CalledOnValidThread());
261 273
262 WebGraphicsContext3D* context3d = output_surface_->context3d(); 274 WebGraphicsContext3D* context3d = output_surface_->context3d();
263 DCHECK(context3d); 275 DCHECK(context3d);
264 GLC(context3d, context3d->bindTexture(texture_target, texture_id)); 276 GLC(context3d, context3d->bindTexture(texture_target, texture_id));
265 GLC(context3d, context3d->texParameteri( 277 GLC(context3d, context3d->texParameteri(
266 texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); 278 texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
267 GLC(context3d, context3d->texParameteri( 279 GLC(context3d, context3d->texParameteri(
268 texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); 280 texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
269 GLC(context3d, context3d->texParameteri( 281 GLC(context3d, context3d->texParameteri(
270 texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); 282 texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
271 GLC(context3d, context3d->texParameteri( 283 GLC(context3d, context3d->texParameteri(
272 texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); 284 texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
273 285
274 ResourceId id = next_id_++; 286 ResourceId id = next_id_++;
275 Resource resource(texture_id, gfx::Size(), 0, GL_LINEAR, 0, TextureUsageAny); 287 Resource resource(texture_id, gfx::Size(), 0, GL_LINEAR, 0, GL_CLAMP_TO_EDGE,
288 TextureUsageAny);
276 resource.external = true; 289 resource.external = true;
277 resource.allocated = true; 290 resource.allocated = true;
278 resources_[id] = resource; 291 resources_[id] = resource;
279 return id; 292 return id;
280 } 293 }
281 294
282 ResourceProvider::ResourceId ResourceProvider::CreateResourceFromTextureMailbox( 295 ResourceProvider::ResourceId ResourceProvider::CreateResourceFromTextureMailbox(
283 const TextureMailbox& mailbox) { 296 const TextureMailbox& mailbox) {
284 DCHECK(thread_checker_.CalledOnValidThread()); 297 DCHECK(thread_checker_.CalledOnValidThread());
285 // Just store the information. Mailbox will be consumed in LockForRead(). 298 // Just store the information. Mailbox will be consumed in LockForRead().
286 ResourceId id = next_id_++; 299 ResourceId id = next_id_++;
287 DCHECK(mailbox.IsValid()); 300 DCHECK(mailbox.IsValid());
288 Resource& resource = resources_[id]; 301 Resource& resource = resources_[id];
289 if (mailbox.IsTexture()) { 302 if (mailbox.IsTexture()) {
290 resource = Resource(0, gfx::Size(), 0, GL_LINEAR, 0, TextureUsageAny); 303 resource = Resource(0, gfx::Size(), 0, GL_LINEAR, 0, GL_CLAMP_TO_EDGE,
304 TextureUsageAny);
291 } else { 305 } else {
292 DCHECK(mailbox.IsSharedMemory()); 306 DCHECK(mailbox.IsSharedMemory());
293 base::SharedMemory* shared_memory = mailbox.shared_memory(); 307 base::SharedMemory* shared_memory = mailbox.shared_memory();
294 DCHECK(shared_memory->memory()); 308 DCHECK(shared_memory->memory());
295 uint8_t* pixels = reinterpret_cast<uint8_t*>(shared_memory->memory()); 309 uint8_t* pixels = reinterpret_cast<uint8_t*>(shared_memory->memory());
296 resource = Resource(pixels, mailbox.shared_memory_size(), 310 resource = Resource(pixels, mailbox.shared_memory_size(),
297 GL_RGBA, GL_LINEAR); 311 GL_RGBA, GL_LINEAR, GL_CLAMP_TO_EDGE);
298 } 312 }
299 resource.external = true; 313 resource.external = true;
300 resource.allocated = true; 314 resource.allocated = true;
301 resource.mailbox = mailbox; 315 resource.mailbox = mailbox;
302 return id; 316 return id;
303 } 317 }
304 318
305 void ResourceProvider::DeleteResource(ResourceId id) { 319 void ResourceProvider::DeleteResource(ResourceId id) {
306 DCHECK(thread_checker_.CalledOnValidThread()); 320 DCHECK(thread_checker_.CalledOnValidThread());
307 ResourceMap::iterator it = resources_.find(id); 321 ResourceMap::iterator it = resources_.find(id);
(...skipping 565 matching lines...) Expand 10 before | Expand all | Expand 10 after
873 // However if the parent is a renderer (e.g. browser tag), it may be ok 887 // However if the parent is a renderer (e.g. browser tag), it may be ok
874 // (and is simpler) to wait. 888 // (and is simpler) to wait.
875 if (it->sync_point) 889 if (it->sync_point)
876 GLC(context3d, context3d->waitSyncPoint(it->sync_point)); 890 GLC(context3d, context3d->waitSyncPoint(it->sync_point));
877 GLC(context3d, texture_id = context3d->createTexture()); 891 GLC(context3d, texture_id = context3d->createTexture());
878 GLC(context3d, context3d->bindTexture(GL_TEXTURE_2D, texture_id)); 892 GLC(context3d, context3d->bindTexture(GL_TEXTURE_2D, texture_id));
879 GLC(context3d, context3d->consumeTextureCHROMIUM(GL_TEXTURE_2D, 893 GLC(context3d, context3d->consumeTextureCHROMIUM(GL_TEXTURE_2D,
880 it->mailbox.name)); 894 it->mailbox.name));
881 ResourceId id = next_id_++; 895 ResourceId id = next_id_++;
882 Resource resource( 896 Resource resource(
883 texture_id, it->size, it->format, it->filter, 0, TextureUsageAny); 897 texture_id, it->size, it->format, it->filter, 0, GL_CLAMP_TO_EDGE,
898 TextureUsageAny);
884 resource.mailbox.SetName(it->mailbox); 899 resource.mailbox.SetName(it->mailbox);
885 // Don't allocate a texture for a child. 900 // Don't allocate a texture for a child.
886 resource.allocated = true; 901 resource.allocated = true;
887 resources_[id] = resource; 902 resources_[id] = resource;
888 child_info.parent_to_child_map[id] = it->id; 903 child_info.parent_to_child_map[id] = it->id;
889 child_info.child_to_parent_map[it->id] = id; 904 child_info.child_to_parent_map[it->id] = id;
890 } 905 }
891 } 906 }
892 907
893 void ResourceProvider::ReceiveFromParent( 908 void ResourceProvider::ReceiveFromParent(
(...skipping 378 matching lines...) Expand 10 before | Expand all | Expand 10 after
1272 return; 1287 return;
1273 1288
1274 // Early out for resources that don't require texture creation. 1289 // Early out for resources that don't require texture creation.
1275 if (resource->texture_pool == 0) 1290 if (resource->texture_pool == 0)
1276 return; 1291 return;
1277 1292
1278 WebGraphicsContext3D* context3d = output_surface_->context3d(); 1293 WebGraphicsContext3D* context3d = output_surface_->context3d();
1279 DCHECK(context3d); 1294 DCHECK(context3d);
1280 // Create and set texture properties. Allocation is delayed until needed. 1295 // Create and set texture properties. Allocation is delayed until needed.
1281 resource->gl_id = CreateTextureId(context3d); 1296 resource->gl_id = CreateTextureId(context3d);
1297 GLC(context3d, context3d->texParameteri(
1298 GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, resource->wrap_mode));
1299 GLC(context3d, context3d->texParameteri(
1300 GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, resource->wrap_mode));
1282 GLC(context3d, context3d->texParameteri(GL_TEXTURE_2D, 1301 GLC(context3d, context3d->texParameteri(GL_TEXTURE_2D,
1283 GL_TEXTURE_POOL_CHROMIUM, 1302 GL_TEXTURE_POOL_CHROMIUM,
1284 resource->texture_pool)); 1303 resource->texture_pool));
1285 if (use_texture_usage_hint_ && resource->hint == TextureUsageFramebuffer) { 1304 if (use_texture_usage_hint_ && resource->hint == TextureUsageFramebuffer) {
1286 GLC(context3d, context3d->texParameteri(GL_TEXTURE_2D, 1305 GLC(context3d, context3d->texParameteri(GL_TEXTURE_2D,
1287 GL_TEXTURE_USAGE_ANGLE, 1306 GL_TEXTURE_USAGE_ANGLE,
1288 GL_FRAMEBUFFER_ATTACHMENT_ANGLE)); 1307 GL_FRAMEBUFFER_ATTACHMENT_ANGLE));
1289 } 1308 }
1290 } 1309 }
1291 1310
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
1439 return stride; 1458 return stride;
1440 } 1459 }
1441 1460
1442 GLint ResourceProvider::GetActiveTextureUnit(WebGraphicsContext3D* context) { 1461 GLint ResourceProvider::GetActiveTextureUnit(WebGraphicsContext3D* context) {
1443 GLint active_unit = 0; 1462 GLint active_unit = 0;
1444 context->getIntegerv(GL_ACTIVE_TEXTURE, &active_unit); 1463 context->getIntegerv(GL_ACTIVE_TEXTURE, &active_unit);
1445 return active_unit; 1464 return active_unit;
1446 } 1465 }
1447 1466
1448 } // namespace cc 1467 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698