Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2010 The Chromium Authors. All rights reserved. | 1 // Copyright 2010 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/gl_renderer.h" | 5 #include "cc/gl_renderer.h" |
| 6 | 6 |
| 7 #include <set> | 7 #include <set> |
| 8 #include <string> | 8 #include <string> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| 11 #include "base/debug/trace_event.h" | 11 #include "base/debug/trace_event.h" |
| 12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/string_split.h" | 13 #include "base/string_split.h" |
| 14 #include "base/string_util.h" | 14 #include "base/string_util.h" |
| 15 #include "build/build_config.h" | 15 #include "build/build_config.h" |
| 16 #include "cc/compositor_frame.h" | 16 #include "cc/compositor_frame.h" |
| 17 #include "cc/compositor_frame_metadata.h" | 17 #include "cc/compositor_frame_metadata.h" |
| 18 #include "cc/damage_tracker.h" | 18 #include "cc/damage_tracker.h" |
| 19 #include "cc/ganesh_resource_provider.h" | |
| 19 #include "cc/geometry_binding.h" | 20 #include "cc/geometry_binding.h" |
| 20 #include "cc/gl_frame_data.h" | 21 #include "cc/gl_frame_data.h" |
| 21 #include "cc/layer_quad.h" | 22 #include "cc/layer_quad.h" |
| 22 #include "cc/math_util.h" | 23 #include "cc/math_util.h" |
| 23 #include "cc/priority_calculator.h" | 24 #include "cc/priority_calculator.h" |
| 24 #include "cc/proxy.h" | 25 #include "cc/proxy.h" |
| 25 #include "cc/render_pass.h" | 26 #include "cc/render_pass.h" |
| 26 #include "cc/render_surface_filters.h" | 27 #include "cc/render_surface_filters.h" |
| 27 #include "cc/scoped_resource.h" | 28 #include "cc/scoped_resource.h" |
| 28 #include "cc/single_thread_proxy.h" | 29 #include "cc/single_thread_proxy.h" |
| 29 #include "cc/stream_video_draw_quad.h" | 30 #include "cc/stream_video_draw_quad.h" |
| 30 #include "cc/texture_draw_quad.h" | 31 #include "cc/texture_draw_quad.h" |
| 31 #include "cc/video_layer_impl.h" | 32 #include "cc/video_layer_impl.h" |
| 32 #include "gpu/GLES2/gl2extchromium.h" | 33 #include "gpu/GLES2/gl2extchromium.h" |
| 33 #include "third_party/WebKit/Source/Platform/chromium/public/WebGraphicsContext3 D.h" | 34 #include "third_party/WebKit/Source/Platform/chromium/public/WebGraphicsContext3 D.h" |
| 34 #include "third_party/WebKit/Source/Platform/chromium/public/WebSharedGraphicsCo ntext3D.h" | |
| 35 #include "third_party/khronos/GLES2/gl2.h" | 35 #include "third_party/khronos/GLES2/gl2.h" |
| 36 #include "third_party/khronos/GLES2/gl2ext.h" | 36 #include "third_party/khronos/GLES2/gl2ext.h" |
| 37 #include "third_party/skia/include/core/SkBitmap.h" | 37 #include "third_party/skia/include/core/SkBitmap.h" |
| 38 #include "third_party/skia/include/core/SkColor.h" | 38 #include "third_party/skia/include/core/SkColor.h" |
| 39 #include "third_party/skia/include/gpu/GrContext.h" | 39 #include "third_party/skia/include/gpu/GrContext.h" |
| 40 #include "third_party/skia/include/gpu/GrTexture.h" | 40 #include "third_party/skia/include/gpu/GrTexture.h" |
| 41 #include "third_party/skia/include/gpu/SkGpuDevice.h" | 41 #include "third_party/skia/include/gpu/SkGpuDevice.h" |
| 42 #include "third_party/skia/include/gpu/SkGrTexturePixelRef.h" | 42 #include "third_party/skia/include/gpu/SkGrTexturePixelRef.h" |
| 43 #include "ui/gfx/quad_f.h" | 43 #include "ui/gfx/quad_f.h" |
| 44 #include "ui/gfx/rect_conversions.h" | 44 #include "ui/gfx/rect_conversions.h" |
| 45 | 45 |
| 46 using WebKit::WebGraphicsContext3D; | 46 using WebKit::WebGraphicsContext3D; |
| 47 using WebKit::WebGraphicsMemoryAllocation; | 47 using WebKit::WebGraphicsMemoryAllocation; |
| 48 using WebKit::WebSharedGraphicsContext3D; | |
| 49 | 48 |
| 50 namespace cc { | 49 namespace cc { |
| 51 | 50 |
| 52 namespace { | 51 namespace { |
| 53 | 52 |
| 54 bool needsIOSurfaceReadbackWorkaround() | 53 bool needsIOSurfaceReadbackWorkaround() |
| 55 { | 54 { |
| 56 #if defined(OS_MACOSX) | 55 #if defined(OS_MACOSX) |
| 57 return true; | 56 return true; |
| 58 #else | 57 #else |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 126 m_capabilities.usingDiscardBackbuffer = extensions.count("GL_CHROMIUM_discar d_backbuffer"); | 125 m_capabilities.usingDiscardBackbuffer = extensions.count("GL_CHROMIUM_discar d_backbuffer"); |
| 127 | 126 |
| 128 m_capabilities.usingEglImage = extensions.count("GL_OES_EGL_image_external") ; | 127 m_capabilities.usingEglImage = extensions.count("GL_OES_EGL_image_external") ; |
| 129 | 128 |
| 130 m_capabilities.maxTextureSize = m_resourceProvider->maxTextureSize(); | 129 m_capabilities.maxTextureSize = m_resourceProvider->maxTextureSize(); |
| 131 m_capabilities.bestTextureFormat = m_resourceProvider->bestTextureFormat(); | 130 m_capabilities.bestTextureFormat = m_resourceProvider->bestTextureFormat(); |
| 132 | 131 |
| 133 // The updater can access textures while the GLRenderer is using them. | 132 // The updater can access textures while the GLRenderer is using them. |
| 134 m_capabilities.allowPartialTextureUpdates = true; | 133 m_capabilities.allowPartialTextureUpdates = true; |
| 135 | 134 |
| 135 m_capabilities.usingOffscreenContext3d = true; | |
| 136 | |
| 136 m_isUsingBindUniform = extensions.count("GL_CHROMIUM_bind_uniform_location") ; | 137 m_isUsingBindUniform = extensions.count("GL_CHROMIUM_bind_uniform_location") ; |
| 137 | 138 |
| 138 // Make sure scissoring starts as disabled. | 139 // Make sure scissoring starts as disabled. |
| 139 GLC(m_context, m_context->disable(GL_SCISSOR_TEST)); | 140 GLC(m_context, m_context->disable(GL_SCISSOR_TEST)); |
| 140 DCHECK(!m_isScissorEnabled); | 141 DCHECK(!m_isScissorEnabled); |
| 141 | 142 |
| 142 if (!initializeSharedObjects()) | 143 if (!initializeSharedObjects()) |
| 143 return false; | 144 return false; |
| 144 | 145 |
| 145 // Make sure the viewport and context gets initialized, even if it is to zer o. | 146 // Make sure the viewport and context gets initialized, even if it is to zer o. |
| (...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 343 float alpha = SkColorGetA(color) / 255.0; | 344 float alpha = SkColorGetA(color) / 255.0; |
| 344 | 345 |
| 345 GLC(context(), context()->uniform4f(program->fragmentShader().colorLocation( ), (SkColorGetR(color) / 255.0) * alpha, (SkColorGetG(color) / 255.0) * alpha, ( SkColorGetB(color) / 255.0) * alpha, alpha)); | 346 GLC(context(), context()->uniform4f(program->fragmentShader().colorLocation( ), (SkColorGetR(color) / 255.0) * alpha, (SkColorGetG(color) / 255.0) * alpha, ( SkColorGetB(color) / 255.0) * alpha, alpha)); |
| 346 | 347 |
| 347 GLC(context(), context()->lineWidth(quad->width)); | 348 GLC(context(), context()->lineWidth(quad->width)); |
| 348 | 349 |
| 349 // The indices for the line are stored in the same array as the triangle ind ices. | 350 // The indices for the line are stored in the same array as the triangle ind ices. |
| 350 GLC(context(), context()->drawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_SHORT, 0 )); | 351 GLC(context(), context()->drawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_SHORT, 0 )); |
| 351 } | 352 } |
| 352 | 353 |
| 353 static WebGraphicsContext3D* getFilterContext(bool hasImplThread) | 354 static inline SkBitmap applyFilters(GLRenderer* renderer, const WebKit::WebFilte rOperations& filters, ScopedResource* sourceResource) |
| 354 { | |
| 355 if (hasImplThread) | |
| 356 return WebSharedGraphicsContext3D::compositorThreadContext(); | |
| 357 else | |
| 358 return WebSharedGraphicsContext3D::mainThreadContext(); | |
| 359 } | |
| 360 | |
| 361 static GrContext* getFilterGrContext(bool hasImplThread) | |
| 362 { | |
| 363 if (hasImplThread) | |
| 364 return WebSharedGraphicsContext3D::compositorThreadGrContext(); | |
| 365 else | |
| 366 return WebSharedGraphicsContext3D::mainThreadGrContext(); | |
| 367 } | |
| 368 | |
| 369 static inline SkBitmap applyFilters(GLRenderer* renderer, const WebKit::WebFilte rOperations& filters, ScopedResource* sourceTexture, bool hasImplThread) | |
| 370 { | 355 { |
| 371 if (filters.isEmpty()) | 356 if (filters.isEmpty()) |
| 372 return SkBitmap(); | 357 return SkBitmap(); |
| 373 | 358 |
| 374 WebGraphicsContext3D* filterContext = getFilterContext(hasImplThread); | 359 if (!renderer->resourceProvider()->ganeshResourceProvider()->has_contexts()) |
| 375 GrContext* filterGrContext = getFilterGrContext(hasImplThread); | |
| 376 | |
| 377 if (!filterContext || !filterGrContext) | |
| 378 return SkBitmap(); | 360 return SkBitmap(); |
| 379 | 361 |
| 380 renderer->context()->flush(); | 362 ResourceProvider::ScopedWriteLockGL lock(renderer->resourceProvider(), sourc eResource->id()); |
| 381 | 363 GaneshResourceProvider::ScopedContextsFlushed ganeshContexts(renderer->resou rceProvider(), renderer->resourceProvider()->ganeshResourceProvider()); |
| 382 ResourceProvider::ScopedWriteLockGL lock(renderer->resourceProvider(), sourc eTexture->id()); | 364 SkBitmap source = RenderSurfaceFilters::apply(filters, lock.textureId(), sou rceResource->size(), ganeshContexts.gr_context()); |
| 383 SkBitmap source = RenderSurfaceFilters::apply(filters, lock.textureId(), sou rceTexture->size(), filterContext, filterGrContext); | |
| 384 return source; | 365 return source; |
| 385 } | 366 } |
| 386 | 367 |
| 387 static SkBitmap applyImageFilter(GLRenderer* renderer, SkImageFilter* filter, Sc opedResource* sourceTexture, bool hasImplThread) | 368 static SkBitmap applyImageFilter(GLRenderer* renderer, SkImageFilter* filter, Sc opedResource* sourceResource) |
| 388 { | 369 { |
| 389 if (!filter) | 370 if (!filter) |
| 390 return SkBitmap(); | 371 return SkBitmap(); |
| 391 | 372 |
| 392 WebGraphicsContext3D* context3d = getFilterContext(hasImplThread); | 373 if (!renderer->resourceProvider()->ganeshResourceProvider()->has_contexts()) |
| 393 GrContext* grContext = getFilterGrContext(hasImplThread); | |
| 394 | |
| 395 if (!context3d || !grContext) | |
| 396 return SkBitmap(); | 374 return SkBitmap(); |
| 397 | 375 |
| 398 renderer->context()->flush(); | 376 ResourceProvider::ScopedWriteLockGL lock(renderer->resourceProvider(), sourc eResource->id()); |
| 399 | 377 |
| 400 ResourceProvider::ScopedWriteLockGL lock(renderer->resourceProvider(), sourc eTexture->id()); | 378 // Flush after locking the resource on the compositor context. |
| 379 GaneshResourceProvider::ScopedContextsFlushed ganeshContexts(renderer->resou rceProvider(), renderer->resourceProvider()->ganeshResourceProvider()); | |
| 401 | 380 |
| 402 // Wrap the source texture in a Ganesh platform texture. | 381 // Wrap the source texture in a Ganesh platform texture. |
| 403 GrPlatformTextureDesc platformTextureDescription; | 382 GrPlatformTextureDesc platformTextureDescription; |
| 404 platformTextureDescription.fWidth = sourceTexture->size().width(); | 383 platformTextureDescription.fWidth = sourceResource->size().width(); |
| 405 platformTextureDescription.fHeight = sourceTexture->size().height(); | 384 platformTextureDescription.fHeight = sourceResource->size().height(); |
| 406 platformTextureDescription.fConfig = kSkia8888_GrPixelConfig; | 385 platformTextureDescription.fConfig = kSkia8888_GrPixelConfig; |
| 407 platformTextureDescription.fTextureHandle = lock.textureId(); | 386 platformTextureDescription.fTextureHandle = lock.textureId(); |
| 408 skia::RefPtr<GrTexture> texture = skia::AdoptRef(grContext->createPlatformTe xture(platformTextureDescription)); | 387 skia::RefPtr<GrTexture> texture = skia::AdoptRef(ganeshContexts.gr_context() ->createPlatformTexture(platformTextureDescription)); |
| 409 | 388 |
| 410 // Place the platform texture inside an SkBitmap. | 389 // Place the platform texture inside an SkBitmap. |
| 411 SkBitmap source; | 390 SkBitmap source; |
| 412 source.setConfig(SkBitmap::kARGB_8888_Config, sourceTexture->size().width(), sourceTexture->size().height()); | 391 source.setConfig(SkBitmap::kARGB_8888_Config, sourceResource->size().width() , sourceResource->size().height()); |
| 413 skia::RefPtr<SkGrPixelRef> pixelRef = skia::AdoptRef(new SkGrPixelRef(textur e.get())); | 392 skia::RefPtr<SkGrPixelRef> pixelRef = skia::AdoptRef(new SkGrPixelRef(textur e.get())); |
| 414 source.setPixelRef(pixelRef.get()); | 393 source.setPixelRef(pixelRef.get()); |
| 415 | 394 |
| 416 // Create a scratch texture for backing store. | 395 // Create a scratch texture for backing store. |
| 417 GrTextureDesc desc; | 396 GrTextureDesc desc; |
| 418 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; | 397 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; |
| 419 desc.fSampleCnt = 0; | 398 desc.fSampleCnt = 0; |
| 420 desc.fWidth = source.width(); | 399 desc.fWidth = source.width(); |
| 421 desc.fHeight = source.height(); | 400 desc.fHeight = source.height(); |
| 422 desc.fConfig = kSkia8888_GrPixelConfig; | 401 desc.fConfig = kSkia8888_GrPixelConfig; |
| 423 GrAutoScratchTexture scratchTexture(grContext, desc, GrContext::kExact_Scrat chTexMatch); | 402 GrAutoScratchTexture scratchTexture(ganeshContexts.gr_context(), desc, GrCon text::kExact_ScratchTexMatch); |
| 424 skia::RefPtr<GrTexture> backingStore = skia::AdoptRef(scratchTexture.detach( )); | 403 skia::RefPtr<GrTexture> backingStore = skia::AdoptRef(scratchTexture.detach( )); |
| 425 | 404 |
| 426 // Create a device and canvas using that backing store. | 405 // Create a device and canvas using that backing store. |
| 427 SkGpuDevice device(grContext, backingStore.get()); | 406 SkGpuDevice device(ganeshContexts.gr_context(), backingStore.get()); |
| 428 SkCanvas canvas(&device); | 407 SkCanvas canvas(&device); |
| 429 | 408 |
| 430 // Draw the source bitmap through the filter to the canvas. | 409 // Draw the source bitmap through the filter to the canvas. |
| 431 SkPaint paint; | 410 SkPaint paint; |
| 432 paint.setImageFilter(filter); | 411 paint.setImageFilter(filter); |
| 433 canvas.clear(0x0); | 412 canvas.clear(0x0); |
| 434 canvas.drawSprite(source, 0, 0, &paint); | 413 canvas.drawSprite(source, 0, 0, &paint); |
| 435 canvas.flush(); | 414 canvas.flush(); |
|
Stephen White
2013/02/07 22:07:52
I hate to be a pain, but couldn't this simply be f
danakj
2013/02/07 22:11:14
I like the guard class because it makes it impossi
bsalomon_chromium
2013/02/08 01:55:57
Calling GrContext::flush() is sufficient. You don'
| |
| 436 context3d->flush(); | |
| 437 return device.accessBitmap(false); | 415 return device.accessBitmap(false); |
| 438 } | 416 } |
| 439 | 417 |
| 440 scoped_ptr<ScopedResource> GLRenderer::drawBackgroundFilters( | 418 scoped_ptr<ScopedResource> GLRenderer::drawBackgroundFilters( |
| 441 DrawingFrame& frame, const RenderPassDrawQuad* quad, | 419 DrawingFrame& frame, const RenderPassDrawQuad* quad, |
| 442 const gfx::Transform& contentsDeviceTransform, | 420 const gfx::Transform& contentsDeviceTransform, |
| 443 const gfx::Transform& contentsDeviceTransformInverse) | 421 const gfx::Transform& contentsDeviceTransformInverse) |
| 444 { | 422 { |
| 445 // This method draws a background filter, which applies a filter to any pixe ls behind the quad and seen through its background. | 423 // This method draws a background filter, which applies a filter to any pixe ls behind the quad and seen through its background. |
| 446 // The algorithm works as follows: | 424 // The algorithm works as follows: |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 474 int top, right, bottom, left; | 452 int top, right, bottom, left; |
| 475 filters.getOutsets(top, right, bottom, left); | 453 filters.getOutsets(top, right, bottom, left); |
| 476 deviceRect.Inset(-left, -top, -right, -bottom); | 454 deviceRect.Inset(-left, -top, -right, -bottom); |
| 477 | 455 |
| 478 deviceRect.Intersect(frame.currentRenderPass->output_rect); | 456 deviceRect.Intersect(frame.currentRenderPass->output_rect); |
| 479 | 457 |
| 480 scoped_ptr<ScopedResource> deviceBackgroundTexture = ScopedResource::create( m_resourceProvider); | 458 scoped_ptr<ScopedResource> deviceBackgroundTexture = ScopedResource::create( m_resourceProvider); |
| 481 if (!getFramebufferTexture(deviceBackgroundTexture.get(), deviceRect)) | 459 if (!getFramebufferTexture(deviceBackgroundTexture.get(), deviceRect)) |
| 482 return scoped_ptr<ScopedResource>(); | 460 return scoped_ptr<ScopedResource>(); |
| 483 | 461 |
| 484 SkBitmap filteredDeviceBackground = applyFilters(this, filters, deviceBackgr oundTexture.get(), m_client->hasImplThread()); | 462 SkBitmap filteredDeviceBackground = applyFilters(this, filters, deviceBackgr oundTexture.get()); |
| 485 if (!filteredDeviceBackground.getTexture()) | 463 if (!filteredDeviceBackground.getTexture()) |
| 486 return scoped_ptr<ScopedResource>(); | 464 return scoped_ptr<ScopedResource>(); |
| 487 | 465 |
| 488 GrTexture* texture = reinterpret_cast<GrTexture*>(filteredDeviceBackground.g etTexture()); | 466 GrTexture* texture = reinterpret_cast<GrTexture*>(filteredDeviceBackground.g etTexture()); |
| 489 int filteredDeviceBackgroundTextureId = texture->getTextureHandle(); | 467 int filteredDeviceBackgroundTextureId = texture->getTextureHandle(); |
| 490 | 468 |
| 491 scoped_ptr<ScopedResource> backgroundTexture = ScopedResource::create(m_reso urceProvider); | 469 scoped_ptr<ScopedResource> backgroundTexture = ScopedResource::create(m_reso urceProvider); |
| 492 if (!backgroundTexture->Allocate(quad->rect.size(), GL_RGBA, ResourceProvide r::TextureUsageFramebuffer)) | 470 if (!backgroundTexture->Allocate(quad->rect.size(), GL_RGBA, ResourceProvide r::TextureUsageFramebuffer)) |
| 493 return scoped_ptr<ScopedResource>(); | 471 return scoped_ptr<ScopedResource>(); |
| 494 | 472 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 527 if (!contentsDeviceTransform.GetInverse(&contentsDeviceTransformInverse)) | 505 if (!contentsDeviceTransform.GetInverse(&contentsDeviceTransformInverse)) |
| 528 return; | 506 return; |
| 529 | 507 |
| 530 scoped_ptr<ScopedResource> backgroundTexture = drawBackgroundFilters( | 508 scoped_ptr<ScopedResource> backgroundTexture = drawBackgroundFilters( |
| 531 frame, quad, contentsDeviceTransform, contentsDeviceTransformInverse); | 509 frame, quad, contentsDeviceTransform, contentsDeviceTransformInverse); |
| 532 | 510 |
| 533 // FIXME: Cache this value so that we don't have to do it for both the surfa ce and its replica. | 511 // FIXME: Cache this value so that we don't have to do it for both the surfa ce and its replica. |
| 534 // Apply filters to the contents texture. | 512 // Apply filters to the contents texture. |
| 535 SkBitmap filterBitmap; | 513 SkBitmap filterBitmap; |
| 536 if (quad->filter) { | 514 if (quad->filter) { |
| 537 filterBitmap = applyImageFilter(this, quad->filter.get(), contentsTextur e, m_client->hasImplThread()); | 515 filterBitmap = applyImageFilter(this, quad->filter.get(), contentsTextur e); |
| 538 } else { | 516 } else { |
| 539 filterBitmap = applyFilters(this, quad->filters, contentsTexture, m_clie nt->hasImplThread()); | 517 filterBitmap = applyFilters(this, quad->filters, contentsTexture); |
| 540 } | 518 } |
| 541 | 519 |
| 542 // Draw the background texture if there is one. | 520 // Draw the background texture if there is one. |
| 543 if (backgroundTexture) { | 521 if (backgroundTexture) { |
| 544 DCHECK(backgroundTexture->size() == quad->rect.size()); | 522 DCHECK(backgroundTexture->size() == quad->rect.size()); |
| 545 ResourceProvider::ScopedReadLockGL lock(m_resourceProvider, backgroundTe xture->id()); | 523 ResourceProvider::ScopedReadLockGL lock(m_resourceProvider, backgroundTe xture->id()); |
| 546 copyTextureToFramebuffer(frame, lock.textureId(), quad->rect, quad->quad Transform()); | 524 copyTextureToFramebuffer(frame, lock.textureId(), quad->rect, quad->quad Transform()); |
| 547 } | 525 } |
| 548 | 526 |
| 549 bool clipped = false; | 527 bool clipped = false; |
| (...skipping 1239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1789 | 1767 |
| 1790 releaseRenderPassTextures(); | 1768 releaseRenderPassTextures(); |
| 1791 } | 1769 } |
| 1792 | 1770 |
| 1793 bool GLRenderer::isContextLost() | 1771 bool GLRenderer::isContextLost() |
| 1794 { | 1772 { |
| 1795 return (m_context->getGraphicsResetStatusARB() != GL_NO_ERROR); | 1773 return (m_context->getGraphicsResetStatusARB() != GL_NO_ERROR); |
| 1796 } | 1774 } |
| 1797 | 1775 |
| 1798 } // namespace cc | 1776 } // namespace cc |
| OLD | NEW |