| OLD | NEW |
| 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 "base/message_loop/message_loop.h" | 5 #include "base/message_loop/message_loop.h" |
| 6 #include "cc/layers/append_quads_data.h" | 6 #include "cc/layers/append_quads_data.h" |
| 7 #include "cc/output/gl_renderer.h" | 7 #include "cc/output/gl_renderer.h" |
| 8 #include "cc/quads/draw_quad.h" | 8 #include "cc/quads/draw_quad.h" |
| 9 #include "cc/quads/picture_draw_quad.h" | 9 #include "cc/quads/picture_draw_quad.h" |
| 10 #include "cc/quads/texture_draw_quad.h" | 10 #include "cc/quads/texture_draw_quad.h" |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 104 rect, | 104 rect, |
| 105 pass_id, | 105 pass_id, |
| 106 0, // mask_resource_id | 106 0, // mask_resource_id |
| 107 gfx::Vector2dF(), // mask_uv_scale | 107 gfx::Vector2dF(), // mask_uv_scale |
| 108 gfx::Size(), // mask_texture_size | 108 gfx::Size(), // mask_texture_size |
| 109 FilterOperations(), // foreground filters | 109 FilterOperations(), // foreground filters |
| 110 gfx::Vector2dF(), // filters scale | 110 gfx::Vector2dF(), // filters scale |
| 111 FilterOperations()); // background filters | 111 FilterOperations()); // background filters |
| 112 } | 112 } |
| 113 | 113 |
| 114 void CreateTestTwoColoredTextureDrawQuad(const gfx::Rect& rect, |
| 115 SkColor texel_color, |
| 116 SkColor texel_stripe_color, |
| 117 SkColor background_color, |
| 118 bool premultiplied_alpha, |
| 119 const SharedQuadState* shared_state, |
| 120 ResourceProvider* resource_provider, |
| 121 RenderPass* render_pass) { |
| 122 SkPMColor pixel_color = premultiplied_alpha |
| 123 ? SkPreMultiplyColor(texel_color) |
| 124 : SkPackARGB32NoCheck(SkColorGetA(texel_color), |
| 125 SkColorGetR(texel_color), |
| 126 SkColorGetG(texel_color), |
| 127 SkColorGetB(texel_color)); |
| 128 SkPMColor pixel_stripe_color = |
| 129 premultiplied_alpha |
| 130 ? SkPreMultiplyColor(texel_stripe_color) |
| 131 : SkPackARGB32NoCheck(SkColorGetA(texel_stripe_color), |
| 132 SkColorGetR(texel_stripe_color), |
| 133 SkColorGetG(texel_stripe_color), |
| 134 SkColorGetB(texel_stripe_color)); |
| 135 std::vector<uint32_t> pixels(rect.size().GetArea(), pixel_color); |
| 136 for (int i = rect.height() / 4; i < (rect.height() * 3 / 4); ++i) { |
| 137 for (int k = rect.width() / 4; k < (rect.width() * 3 / 4); ++k) { |
| 138 pixels[i * rect.width() + k] = pixel_stripe_color; |
| 139 } |
| 140 } |
| 141 ResourceProvider::ResourceId resource = resource_provider->CreateResource( |
| 142 rect.size(), GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, |
| 143 RGBA_8888); |
| 144 resource_provider->SetPixels(resource, |
| 145 reinterpret_cast<uint8_t*>(&pixels.front()), |
| 146 rect, rect, gfx::Vector2d()); |
| 147 |
| 148 float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f}; |
| 149 const gfx::PointF uv_top_left(0.0f, 0.0f); |
| 150 const gfx::PointF uv_bottom_right(1.0f, 1.0f); |
| 151 const bool flipped = false; |
| 152 const bool nearest_neighbor = false; |
| 153 TextureDrawQuad* quad = |
| 154 render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); |
| 155 quad->SetNew(shared_state, rect, gfx::Rect(), rect, resource, |
| 156 premultiplied_alpha, uv_top_left, uv_bottom_right, |
| 157 background_color, vertex_opacity, flipped, nearest_neighbor); |
| 158 } |
| 159 |
| 114 void CreateTestTextureDrawQuad(const gfx::Rect& rect, | 160 void CreateTestTextureDrawQuad(const gfx::Rect& rect, |
| 115 SkColor texel_color, | 161 SkColor texel_color, |
| 116 SkColor background_color, | 162 SkColor background_color, |
| 117 bool premultiplied_alpha, | 163 bool premultiplied_alpha, |
| 118 const SharedQuadState* shared_state, | 164 const SharedQuadState* shared_state, |
| 119 ResourceProvider* resource_provider, | 165 ResourceProvider* resource_provider, |
| 120 RenderPass* render_pass) { | 166 RenderPass* render_pass) { |
| 121 SkPMColor pixel_color = premultiplied_alpha ? | 167 SkPMColor pixel_color = premultiplied_alpha ? |
| 122 SkPreMultiplyColor(texel_color) : | 168 SkPreMultiplyColor(texel_color) : |
| 123 SkPackARGB32NoCheck(SkColorGetA(texel_color), | 169 SkPackARGB32NoCheck(SkColorGetA(texel_color), |
| 124 SkColorGetR(texel_color), | 170 SkColorGetR(texel_color), |
| 125 SkColorGetG(texel_color), | 171 SkColorGetG(texel_color), |
| 126 SkColorGetB(texel_color)); | 172 SkColorGetB(texel_color)); |
| 127 size_t num_pixels = static_cast<size_t>(rect.width()) * rect.height(); | 173 size_t num_pixels = static_cast<size_t>(rect.width()) * rect.height(); |
| 128 std::vector<uint32_t> pixels(num_pixels, pixel_color); | 174 std::vector<uint32_t> pixels(num_pixels, pixel_color); |
| 129 | 175 |
| 130 ResourceProvider::ResourceId resource = resource_provider->CreateResource( | 176 ResourceProvider::ResourceId resource = resource_provider->CreateResource( |
| 131 rect.size(), GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, | 177 rect.size(), GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, |
| 132 RGBA_8888); | 178 RGBA_8888); |
| 133 resource_provider->CopyToResource( | 179 resource_provider->CopyToResource( |
| 134 resource, reinterpret_cast<uint8_t*>(&pixels.front()), rect.size()); | 180 resource, reinterpret_cast<uint8_t*>(&pixels.front()), rect.size()); |
| 135 | 181 |
| 136 float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f}; | 182 float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f}; |
| 137 | 183 |
| 184 const gfx::PointF uv_top_left(0.0f, 0.0f); |
| 185 const gfx::PointF uv_bottom_right(1.0f, 1.0f); |
| 186 const bool flipped = false; |
| 187 const bool nearest_neighbor = false; |
| 138 TextureDrawQuad* quad = | 188 TextureDrawQuad* quad = |
| 139 render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); | 189 render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); |
| 140 quad->SetNew(shared_state, | 190 quad->SetNew(shared_state, rect, gfx::Rect(), rect, resource, |
| 141 rect, | 191 premultiplied_alpha, uv_top_left, uv_bottom_right, |
| 142 gfx::Rect(), | 192 background_color, vertex_opacity, flipped, nearest_neighbor); |
| 143 rect, | 193 } |
| 144 resource, | 194 |
| 145 premultiplied_alpha, | 195 void CreateTestYUVVideoDrawQuad_FromVideoFrame( |
| 146 gfx::PointF(0.0f, 0.0f), // uv_top_left | 196 const SharedQuadState* shared_state, |
| 147 gfx::PointF(1.0f, 1.0f), // uv_bottom_right | 197 scoped_refptr<media::VideoFrame> video_frame, |
| 148 background_color, | 198 uint8 alpha_value, |
| 149 vertex_opacity, | 199 const gfx::RectF& tex_coord_rect, |
| 150 false, // flipped | 200 RenderPass* render_pass, |
| 151 false); // nearest_neighbor | 201 VideoResourceUpdater* video_resource_updater, |
| 202 const gfx::Rect& rect, |
| 203 ResourceProvider* resource_provider) { |
| 204 const bool with_alpha = (video_frame->format() == media::VideoFrame::YV12A); |
| 205 const YUVVideoDrawQuad::ColorSpace color_space = |
| 206 (video_frame->format() == media::VideoFrame::YV12J |
| 207 ? YUVVideoDrawQuad::JPEG |
| 208 : YUVVideoDrawQuad::REC_601); |
| 209 const gfx::Rect opaque_rect(0, 0, 0, 0); |
| 210 |
| 211 if (with_alpha) { |
| 212 memset(video_frame->data(media::VideoFrame::kAPlane), alpha_value, |
| 213 video_frame->stride(media::VideoFrame::kAPlane) * |
| 214 video_frame->rows(media::VideoFrame::kAPlane)); |
| 215 } |
| 216 |
| 217 VideoFrameExternalResources resources = |
| 218 video_resource_updater->CreateExternalResourcesFromVideoFrame( |
| 219 video_frame); |
| 220 |
| 221 EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type); |
| 222 EXPECT_EQ(media::VideoFrame::NumPlanes(video_frame->format()), |
| 223 resources.mailboxes.size()); |
| 224 EXPECT_EQ(media::VideoFrame::NumPlanes(video_frame->format()), |
| 225 resources.release_callbacks.size()); |
| 226 |
| 227 ResourceProvider::ResourceId y_resource = |
| 228 resource_provider->CreateResourceFromTextureMailbox( |
| 229 resources.mailboxes[media::VideoFrame::kYPlane], |
| 230 SingleReleaseCallbackImpl::Create( |
| 231 resources.release_callbacks[media::VideoFrame::kYPlane])); |
| 232 ResourceProvider::ResourceId u_resource = |
| 233 resource_provider->CreateResourceFromTextureMailbox( |
| 234 resources.mailboxes[media::VideoFrame::kUPlane], |
| 235 SingleReleaseCallbackImpl::Create( |
| 236 resources.release_callbacks[media::VideoFrame::kUPlane])); |
| 237 ResourceProvider::ResourceId v_resource = |
| 238 resource_provider->CreateResourceFromTextureMailbox( |
| 239 resources.mailboxes[media::VideoFrame::kVPlane], |
| 240 SingleReleaseCallbackImpl::Create( |
| 241 resources.release_callbacks[media::VideoFrame::kVPlane])); |
| 242 ResourceProvider::ResourceId a_resource = 0; |
| 243 if (with_alpha) { |
| 244 a_resource = resource_provider->CreateResourceFromTextureMailbox( |
| 245 resources.mailboxes[media::VideoFrame::kAPlane], |
| 246 SingleReleaseCallbackImpl::Create( |
| 247 resources.release_callbacks[media::VideoFrame::kAPlane])); |
| 248 } |
| 249 |
| 250 YUVVideoDrawQuad* yuv_quad = |
| 251 render_pass->CreateAndAppendDrawQuad<YUVVideoDrawQuad>(); |
| 252 yuv_quad->SetNew(shared_state, rect, opaque_rect, rect, tex_coord_rect, |
| 253 video_frame->coded_size(), y_resource, u_resource, |
| 254 v_resource, a_resource, color_space); |
| 255 } |
| 256 |
| 257 void CreateTestYUVVideoDrawQuad_Striped( |
| 258 const SharedQuadState* shared_state, |
| 259 media::VideoFrame::Format format, |
| 260 bool is_transparent, |
| 261 const gfx::RectF& tex_coord_rect, |
| 262 RenderPass* render_pass, |
| 263 VideoResourceUpdater* video_resource_updater, |
| 264 const gfx::Rect& rect, |
| 265 ResourceProvider* resource_provider) { |
| 266 scoped_refptr<media::VideoFrame> video_frame = media::VideoFrame::CreateFrame( |
| 267 format, rect.size(), rect, rect.size(), base::TimeDelta()); |
| 268 |
| 269 // YUV values representing a striped pattern, for validating texture |
| 270 // coordinates for sampling. |
| 271 uint8_t y_value = 0; |
| 272 uint8_t u_value = 0; |
| 273 uint8_t v_value = 0; |
| 274 for (int i = 0; i < video_frame->rows(media::VideoFrame::kYPlane); ++i) { |
| 275 uint8_t* y_row = video_frame->data(media::VideoFrame::kYPlane) + |
| 276 video_frame->stride(media::VideoFrame::kYPlane) * i; |
| 277 for (int j = 0; j < video_frame->row_bytes(media::VideoFrame::kYPlane); |
| 278 ++j) { |
| 279 y_row[j] = (y_value += 1); |
| 280 } |
| 281 } |
| 282 for (int i = 0; i < video_frame->rows(media::VideoFrame::kUPlane); ++i) { |
| 283 uint8_t* u_row = video_frame->data(media::VideoFrame::kUPlane) + |
| 284 video_frame->stride(media::VideoFrame::kUPlane) * i; |
| 285 uint8_t* v_row = video_frame->data(media::VideoFrame::kVPlane) + |
| 286 video_frame->stride(media::VideoFrame::kVPlane) * i; |
| 287 for (int j = 0; j < video_frame->row_bytes(media::VideoFrame::kUPlane); |
| 288 ++j) { |
| 289 u_row[j] = (u_value += 3); |
| 290 v_row[j] = (v_value += 5); |
| 291 } |
| 292 } |
| 293 uint8 alpha_value = is_transparent ? 0 : 128; |
| 294 CreateTestYUVVideoDrawQuad_FromVideoFrame( |
| 295 shared_state, video_frame, alpha_value, tex_coord_rect, render_pass, |
| 296 video_resource_updater, rect, resource_provider); |
| 297 } |
| 298 |
| 299 // Creates a video frame of size background_size filled with yuv_background, |
| 300 // and then draws a foreground rectangle in a different color on top of |
| 301 // that. The foreground rectangle must have coordinates that are divisible |
| 302 // by 2 because YUV is a block format. |
| 303 void CreateTestYUVVideoDrawQuad_TwoColor( |
| 304 const SharedQuadState* shared_state, |
| 305 media::VideoFrame::Format format, |
| 306 bool is_transparent, |
| 307 const gfx::RectF& tex_coord_rect, |
| 308 const gfx::Size& background_size, |
| 309 uint8 y_background, |
| 310 uint8 u_background, |
| 311 uint8 v_background, |
| 312 const gfx::Rect& foreground_rect, |
| 313 uint8 y_foreground, |
| 314 uint8 u_foreground, |
| 315 uint8 v_foreground, |
| 316 RenderPass* render_pass, |
| 317 VideoResourceUpdater* video_resource_updater, |
| 318 ResourceProvider* resource_provider) { |
| 319 const gfx::Rect rect(background_size); |
| 320 |
| 321 scoped_refptr<media::VideoFrame> video_frame = |
| 322 media::VideoFrame::CreateFrame(format, background_size, foreground_rect, |
| 323 foreground_rect.size(), base::TimeDelta()); |
| 324 |
| 325 int planes[] = {media::VideoFrame::kYPlane, |
| 326 media::VideoFrame::kUPlane, |
| 327 media::VideoFrame::kVPlane}; |
| 328 uint8 yuv_background[] = {y_background, u_background, v_background}; |
| 329 uint8 yuv_foreground[] = {y_foreground, u_foreground, v_foreground}; |
| 330 int sample_size[] = {1, 2, 2}; |
| 331 |
| 332 for (int i = 0; i < 3; ++i) { |
| 333 memset(video_frame->data(planes[i]), yuv_background[i], |
| 334 video_frame->stride(planes[i]) * video_frame->rows(planes[i])); |
| 335 } |
| 336 |
| 337 for (int i = 0; i < 3; ++i) { |
| 338 // Since yuv encoding uses block encoding, widths have to be divisible |
| 339 // by the sample size in order for this function to behave properly. |
| 340 DCHECK_EQ(foreground_rect.x() % sample_size[i], 0); |
| 341 DCHECK_EQ(foreground_rect.y() % sample_size[i], 0); |
| 342 DCHECK_EQ(foreground_rect.width() % sample_size[i], 0); |
| 343 DCHECK_EQ(foreground_rect.height() % sample_size[i], 0); |
| 344 |
| 345 gfx::Rect sample_rect(foreground_rect.x() / sample_size[i], |
| 346 foreground_rect.y() / sample_size[i], |
| 347 foreground_rect.width() / sample_size[i], |
| 348 foreground_rect.height() / sample_size[i]); |
| 349 for (int y = sample_rect.y(); y < sample_rect.bottom(); ++y) { |
| 350 for (int x = sample_rect.x(); x < sample_rect.right(); ++x) { |
| 351 size_t offset = y * video_frame->stride(planes[i]) + x; |
| 352 video_frame->data(planes[i])[offset] = yuv_foreground[i]; |
| 353 } |
| 354 } |
| 355 } |
| 356 |
| 357 uint8 alpha_value = 255; |
| 358 CreateTestYUVVideoDrawQuad_FromVideoFrame( |
| 359 shared_state, video_frame, alpha_value, tex_coord_rect, render_pass, |
| 360 video_resource_updater, rect, resource_provider); |
| 361 } |
| 362 |
| 363 void CreateTestYUVVideoDrawQuad_Solid( |
| 364 const SharedQuadState* shared_state, |
| 365 media::VideoFrame::Format format, |
| 366 bool is_transparent, |
| 367 const gfx::RectF& tex_coord_rect, |
| 368 uint8 y, |
| 369 uint8 u, |
| 370 uint8 v, |
| 371 RenderPass* render_pass, |
| 372 VideoResourceUpdater* video_resource_updater, |
| 373 const gfx::Rect& rect, |
| 374 ResourceProvider* resource_provider) { |
| 375 scoped_refptr<media::VideoFrame> video_frame = media::VideoFrame::CreateFrame( |
| 376 format, rect.size(), rect, rect.size(), base::TimeDelta()); |
| 377 |
| 378 // YUV values of a solid, constant, color. Useful for testing that color |
| 379 // space/color range are being handled properly. |
| 380 memset(video_frame->data(media::VideoFrame::kYPlane), y, |
| 381 video_frame->stride(media::VideoFrame::kYPlane) * |
| 382 video_frame->rows(media::VideoFrame::kYPlane)); |
| 383 memset(video_frame->data(media::VideoFrame::kUPlane), u, |
| 384 video_frame->stride(media::VideoFrame::kUPlane) * |
| 385 video_frame->rows(media::VideoFrame::kUPlane)); |
| 386 memset(video_frame->data(media::VideoFrame::kVPlane), v, |
| 387 video_frame->stride(media::VideoFrame::kVPlane) * |
| 388 video_frame->rows(media::VideoFrame::kVPlane)); |
| 389 |
| 390 uint8 alpha_value = is_transparent ? 0 : 128; |
| 391 CreateTestYUVVideoDrawQuad_FromVideoFrame( |
| 392 shared_state, video_frame, alpha_value, tex_coord_rect, render_pass, |
| 393 video_resource_updater, rect, resource_provider); |
| 152 } | 394 } |
| 153 | 395 |
| 154 typedef ::testing::Types<GLRenderer, | 396 typedef ::testing::Types<GLRenderer, |
| 155 SoftwareRenderer, | 397 SoftwareRenderer, |
| 156 GLRendererWithExpandedViewport, | 398 GLRendererWithExpandedViewport, |
| 157 SoftwareRendererWithExpandedViewport> RendererTypes; | 399 SoftwareRendererWithExpandedViewport> RendererTypes; |
| 158 TYPED_TEST_CASE(RendererPixelTest, RendererTypes); | 400 TYPED_TEST_CASE(RendererPixelTest, RendererTypes); |
| 159 | 401 |
| 160 template <typename RendererType> | 402 template <typename RendererType> |
| 161 class SoftwareRendererPixelTest : public RendererPixelTest<RendererType> {}; | 403 class SoftwareRendererPixelTest : public RendererPixelTest<RendererType> {}; |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 316 | 558 |
| 317 RenderPassList pass_list; | 559 RenderPassList pass_list; |
| 318 pass_list.push_back(pass.Pass()); | 560 pass_list.push_back(pass.Pass()); |
| 319 | 561 |
| 320 EXPECT_TRUE(this->RunPixelTest( | 562 EXPECT_TRUE(this->RunPixelTest( |
| 321 &pass_list, | 563 &pass_list, |
| 322 base::FilePath(FILE_PATH_LITERAL("green_alpha.png")), | 564 base::FilePath(FILE_PATH_LITERAL("green_alpha.png")), |
| 323 FuzzyPixelOffByOneComparator(true))); | 565 FuzzyPixelOffByOneComparator(true))); |
| 324 } | 566 } |
| 325 | 567 |
| 568 template <typename QuadType> |
| 569 static const char* IntersectingQuadImage() { |
| 570 return "intersecting_blue_green_squares.png"; |
| 571 } |
| 572 template <> |
| 573 const char* IntersectingQuadImage<SolidColorDrawQuad>() { |
| 574 return "intersecting_blue_green.png"; |
| 575 } |
| 576 template <> |
| 577 const char* IntersectingQuadImage<YUVVideoDrawQuad>() { |
| 578 return "intersecting_blue_green_squares_video.png"; |
| 579 } |
| 580 |
| 581 template <typename TypeParam> |
| 582 class IntersectingQuadPixelTest : public RendererPixelTest<TypeParam> { |
| 583 protected: |
| 584 void SetupQuadStateAndRenderPass() { |
| 585 // This sets up a pair of draw quads. They are both rotated |
| 586 // relative to the root plane, they are also rotated relative to each other. |
| 587 // The intersect in the middle at a non-perpendicular angle so that any |
| 588 // errors are hopefully magnified. |
| 589 // The quads should intersect correctly, as in the front quad should only |
| 590 // be partially in front of the back quad, and partially behind. |
| 591 |
| 592 viewport_rect_ = gfx::Rect(this->device_viewport_size_); |
| 593 quad_rect_ = gfx::Rect(0, 0, this->device_viewport_size_.width(), |
| 594 this->device_viewport_size_.height() / 2.0); |
| 595 |
| 596 RenderPassId id(1, 1); |
| 597 render_pass_ = CreateTestRootRenderPass(id, viewport_rect_); |
| 598 |
| 599 // Create the front quad rotated on the Z and Y axis. |
| 600 gfx::Transform trans; |
| 601 trans.Translate3d(0, 0, 0.707 * this->device_viewport_size_.width() / 2.0); |
| 602 trans.RotateAboutZAxis(45.0); |
| 603 trans.RotateAboutYAxis(45.0); |
| 604 front_quad_state_ = |
| 605 CreateTestSharedQuadState(trans, viewport_rect_, render_pass_.get()); |
| 606 front_quad_state_->clip_rect = quad_rect_; |
| 607 // Make sure they end up in a 3d sorting context. |
| 608 front_quad_state_->sorting_context_id = 1; |
| 609 |
| 610 // Create the back quad, and rotate on just the y axis. This will intersect |
| 611 // the first quad partially. |
| 612 trans = gfx::Transform(); |
| 613 trans.Translate3d(0, 0, -0.707 * this->device_viewport_size_.width() / 2.0); |
| 614 trans.RotateAboutYAxis(-45.0); |
| 615 back_quad_state_ = |
| 616 CreateTestSharedQuadState(trans, viewport_rect_, render_pass_.get()); |
| 617 back_quad_state_->sorting_context_id = 1; |
| 618 back_quad_state_->clip_rect = quad_rect_; |
| 619 } |
| 620 template <typename T> |
| 621 void AppendBackgroundAndRunTest() { |
| 622 SharedQuadState* background_quad_state = CreateTestSharedQuadState( |
| 623 gfx::Transform(), viewport_rect_, render_pass_.get()); |
| 624 SolidColorDrawQuad* background_quad = |
| 625 render_pass_->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| 626 background_quad->SetNew(background_quad_state, viewport_rect_, |
| 627 viewport_rect_, SK_ColorWHITE, false); |
| 628 pass_list_.push_back(render_pass_.Pass()); |
| 629 const char* fileName = IntersectingQuadImage<T>(); |
| 630 EXPECT_TRUE(this->RunPixelTest( |
| 631 &pass_list_, base::FilePath(fileName), |
| 632 FuzzyPixelComparator(false, 2.f, 0.f, 256.f, 256, 0.f))); |
| 633 } |
| 634 template <typename T> |
| 635 T* CreateAndAppendDrawQuad() { |
| 636 return render_pass_->CreateAndAppendDrawQuad<T>(); |
| 637 } |
| 638 |
| 639 scoped_ptr<RenderPass> render_pass_; |
| 640 gfx::Rect viewport_rect_; |
| 641 SharedQuadState* front_quad_state_; |
| 642 SharedQuadState* back_quad_state_; |
| 643 gfx::Rect quad_rect_; |
| 644 RenderPassList pass_list_; |
| 645 }; |
| 646 |
| 647 template <typename TypeParam> |
| 648 class IntersectingQuadGLPixelTest |
| 649 : public IntersectingQuadPixelTest<TypeParam> { |
| 650 public: |
| 651 void SetUp() override { |
| 652 IntersectingQuadPixelTest<TypeParam>::SetUp(); |
| 653 video_resource_updater_.reset( |
| 654 new VideoResourceUpdater(this->output_surface_->context_provider(), |
| 655 this->resource_provider_.get())); |
| 656 video_resource_updater2_.reset( |
| 657 new VideoResourceUpdater(this->output_surface_->context_provider(), |
| 658 this->resource_provider_.get())); |
| 659 } |
| 660 |
| 661 protected: |
| 662 scoped_ptr<VideoResourceUpdater> video_resource_updater_; |
| 663 scoped_ptr<VideoResourceUpdater> video_resource_updater2_; |
| 664 }; |
| 665 |
| 666 template <typename TypeParam> |
| 667 class IntersectingQuadSoftwareTest |
| 668 : public IntersectingQuadPixelTest<TypeParam> {}; |
| 669 |
| 670 typedef ::testing::Types<SoftwareRenderer, SoftwareRendererWithExpandedViewport> |
| 671 SoftwareRendererTypes; |
| 672 typedef ::testing::Types<GLRenderer, GLRendererWithExpandedViewport> |
| 673 GLRendererTypes; |
| 674 |
| 675 TYPED_TEST_CASE(IntersectingQuadPixelTest, RendererTypes); |
| 676 TYPED_TEST_CASE(IntersectingQuadGLPixelTest, GLRendererTypes); |
| 677 TYPED_TEST_CASE(IntersectingQuadSoftwareTest, SoftwareRendererTypes); |
| 678 |
| 679 TYPED_TEST(IntersectingQuadPixelTest, SolidColorQuads) { |
| 680 this->SetupQuadStateAndRenderPass(); |
| 681 |
| 682 SolidColorDrawQuad* quad = |
| 683 this->template CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| 684 SolidColorDrawQuad* quad2 = |
| 685 this->template CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| 686 |
| 687 quad->SetNew(this->front_quad_state_, this->quad_rect_, this->quad_rect_, |
| 688 SK_ColorBLUE, false); |
| 689 quad2->SetNew(this->back_quad_state_, this->quad_rect_, this->quad_rect_, |
| 690 SK_ColorGREEN, false); |
| 691 SCOPED_TRACE("IntersectingSolidColorQuads"); |
| 692 this->template AppendBackgroundAndRunTest<SolidColorDrawQuad>(); |
| 693 } |
| 694 |
| 695 template <typename TypeParam> |
| 696 SkColor GetColor(const SkColor& color) { |
| 697 return color; |
| 698 } |
| 699 |
| 700 template <> |
| 701 SkColor GetColor<GLRenderer>(const SkColor& color) { |
| 702 return SkColorSetARGB(SkColorGetA(color), SkColorGetB(color), |
| 703 SkColorGetG(color), SkColorGetR(color)); |
| 704 } |
| 705 template <> |
| 706 SkColor GetColor<GLRendererWithExpandedViewport>(const SkColor& color) { |
| 707 return GetColor<GLRenderer>(color); |
| 708 } |
| 709 |
| 710 TYPED_TEST(IntersectingQuadPixelTest, TexturedQuads) { |
| 711 this->SetupQuadStateAndRenderPass(); |
| 712 CreateTestTwoColoredTextureDrawQuad( |
| 713 this->quad_rect_, GetColor<TypeParam>(SkColorSetARGB(255, 0, 0, 0)), |
| 714 GetColor<TypeParam>(SkColorSetARGB(255, 0, 0, 255)), SK_ColorTRANSPARENT, |
| 715 true, this->front_quad_state_, this->resource_provider_.get(), |
| 716 this->render_pass_.get()); |
| 717 CreateTestTwoColoredTextureDrawQuad( |
| 718 this->quad_rect_, GetColor<TypeParam>(SkColorSetARGB(255, 0, 255, 0)), |
| 719 GetColor<TypeParam>(SkColorSetARGB(255, 0, 0, 0)), SK_ColorTRANSPARENT, |
| 720 true, this->back_quad_state_, this->resource_provider_.get(), |
| 721 this->render_pass_.get()); |
| 722 |
| 723 SCOPED_TRACE("IntersectingTexturedQuads"); |
| 724 this->template AppendBackgroundAndRunTest<TextureDrawQuad>(); |
| 725 } |
| 726 |
| 727 TYPED_TEST(IntersectingQuadSoftwareTest, PictureQuads) { |
| 728 this->SetupQuadStateAndRenderPass(); |
| 729 gfx::RectF outer_rect(this->quad_rect_); |
| 730 gfx::RectF inner_rect(this->quad_rect_.x() + (this->quad_rect_.width() / 4), |
| 731 this->quad_rect_.y() + (this->quad_rect_.height() / 4), |
| 732 this->quad_rect_.width() / 2, |
| 733 this->quad_rect_.height() / 2); |
| 734 |
| 735 SkPaint black_paint; |
| 736 black_paint.setColor(SK_ColorBLACK); |
| 737 SkPaint blue_paint; |
| 738 blue_paint.setColor(SK_ColorBLUE); |
| 739 SkPaint green_paint; |
| 740 green_paint.setColor(SK_ColorGREEN); |
| 741 |
| 742 scoped_ptr<FakePicturePile> blue_recording = |
| 743 FakePicturePile::CreateFilledPile(gfx::Size(1000, 1000), |
| 744 this->quad_rect_.size()); |
| 745 blue_recording->add_draw_rect_with_paint(outer_rect, black_paint); |
| 746 blue_recording->add_draw_rect_with_paint(inner_rect, blue_paint); |
| 747 blue_recording->RerecordPile(); |
| 748 scoped_refptr<FakePicturePileImpl> blue_pile = |
| 749 FakePicturePileImpl::CreateFromPile(blue_recording.get(), nullptr); |
| 750 |
| 751 PictureDrawQuad* blue_quad = |
| 752 this->render_pass_->template CreateAndAppendDrawQuad<PictureDrawQuad>(); |
| 753 |
| 754 blue_quad->SetNew(this->front_quad_state_, this->quad_rect_, gfx::Rect(), |
| 755 this->quad_rect_, this->quad_rect_, this->quad_rect_.size(), |
| 756 false, RGBA_8888, this->quad_rect_, 1.f, blue_pile); |
| 757 |
| 758 scoped_ptr<FakePicturePile> green_recording = |
| 759 FakePicturePile::CreateFilledPile(this->quad_rect_.size(), |
| 760 this->quad_rect_.size()); |
| 761 green_recording->add_draw_rect_with_paint(outer_rect, green_paint); |
| 762 green_recording->add_draw_rect_with_paint(inner_rect, black_paint); |
| 763 green_recording->RerecordPile(); |
| 764 scoped_refptr<FakePicturePileImpl> green_pile = |
| 765 FakePicturePileImpl::CreateFromPile(green_recording.get(), nullptr); |
| 766 |
| 767 PictureDrawQuad* green_quad = |
| 768 this->render_pass_->template CreateAndAppendDrawQuad<PictureDrawQuad>(); |
| 769 green_quad->SetNew(this->back_quad_state_, this->quad_rect_, gfx::Rect(), |
| 770 this->quad_rect_, this->quad_rect_, |
| 771 this->quad_rect_.size(), false, RGBA_8888, |
| 772 this->quad_rect_, 1.f, green_pile); |
| 773 SCOPED_TRACE("IntersectingPictureQuadsPass"); |
| 774 this->template AppendBackgroundAndRunTest<PictureDrawQuad>(); |
| 775 } |
| 776 |
| 777 TYPED_TEST(IntersectingQuadPixelTest, RenderPassQuads) { |
| 778 this->SetupQuadStateAndRenderPass(); |
| 779 RenderPassId child_pass_id1(2, 2); |
| 780 RenderPassId child_pass_id2(2, 3); |
| 781 scoped_ptr<RenderPass> child_pass1 = |
| 782 CreateTestRenderPass(child_pass_id1, this->quad_rect_, gfx::Transform()); |
| 783 SharedQuadState* child1_quad_state = CreateTestSharedQuadState( |
| 784 gfx::Transform(), this->quad_rect_, child_pass1.get()); |
| 785 scoped_ptr<RenderPass> child_pass2 = |
| 786 CreateTestRenderPass(child_pass_id2, this->quad_rect_, gfx::Transform()); |
| 787 SharedQuadState* child2_quad_state = CreateTestSharedQuadState( |
| 788 gfx::Transform(), this->quad_rect_, child_pass2.get()); |
| 789 |
| 790 CreateTestTwoColoredTextureDrawQuad( |
| 791 this->quad_rect_, GetColor<TypeParam>(SkColorSetARGB(255, 0, 0, 0)), |
| 792 GetColor<TypeParam>(SkColorSetARGB(255, 0, 0, 255)), SK_ColorTRANSPARENT, |
| 793 true, child1_quad_state, this->resource_provider_.get(), |
| 794 child_pass1.get()); |
| 795 CreateTestTwoColoredTextureDrawQuad( |
| 796 this->quad_rect_, GetColor<TypeParam>(SkColorSetARGB(255, 0, 255, 0)), |
| 797 GetColor<TypeParam>(SkColorSetARGB(255, 0, 0, 0)), SK_ColorTRANSPARENT, |
| 798 true, child2_quad_state, this->resource_provider_.get(), |
| 799 child_pass2.get()); |
| 800 |
| 801 CreateTestRenderPassDrawQuad(this->front_quad_state_, this->quad_rect_, |
| 802 child_pass_id1, this->render_pass_.get()); |
| 803 CreateTestRenderPassDrawQuad(this->back_quad_state_, this->quad_rect_, |
| 804 child_pass_id2, this->render_pass_.get()); |
| 805 |
| 806 this->pass_list_.push_back(child_pass1.Pass()); |
| 807 this->pass_list_.push_back(child_pass2.Pass()); |
| 808 SCOPED_TRACE("IntersectingRenderQuadsPass"); |
| 809 this->template AppendBackgroundAndRunTest<RenderPassDrawQuad>(); |
| 810 } |
| 811 |
| 812 TYPED_TEST(IntersectingQuadGLPixelTest, YUVVideoQuads) { |
| 813 this->SetupQuadStateAndRenderPass(); |
| 814 gfx::Rect inner_rect( |
| 815 (this->quad_rect_.x() + (this->quad_rect_.width() / 4) & ~0xF), |
| 816 (this->quad_rect_.y() + (this->quad_rect_.height() / 4) & ~0xF), |
| 817 (this->quad_rect_.width() / 2) & ~0xF, |
| 818 (this->quad_rect_.height() / 2) & ~0xF); |
| 819 |
| 820 CreateTestYUVVideoDrawQuad_TwoColor( |
| 821 this->front_quad_state_, media::VideoFrame::YV12J, false, |
| 822 gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), this->quad_rect_.size(), 0, 128, 128, |
| 823 inner_rect, 29, 255, 107, this->render_pass_.get(), |
| 824 this->video_resource_updater_.get(), this->resource_provider_.get()); |
| 825 |
| 826 CreateTestYUVVideoDrawQuad_TwoColor( |
| 827 this->back_quad_state_, media::VideoFrame::YV12J, false, |
| 828 gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), this->quad_rect_.size(), 149, 43, 21, |
| 829 inner_rect, 0, 128, 128, this->render_pass_.get(), |
| 830 this->video_resource_updater2_.get(), this->resource_provider_.get()); |
| 831 |
| 832 SCOPED_TRACE("IntersectingVideoQuads"); |
| 833 this->template AppendBackgroundAndRunTest<YUVVideoDrawQuad>(); |
| 834 } |
| 835 |
| 326 // TODO(skaslev): The software renderer does not support non-premultplied alpha. | 836 // TODO(skaslev): The software renderer does not support non-premultplied alpha. |
| 327 TEST_F(GLRendererPixelTest, NonPremultipliedTextureWithoutBackground) { | 837 TEST_F(GLRendererPixelTest, NonPremultipliedTextureWithoutBackground) { |
| 328 gfx::Rect rect(this->device_viewport_size_); | 838 gfx::Rect rect(this->device_viewport_size_); |
| 329 | 839 |
| 330 RenderPassId id(1, 1); | 840 RenderPassId id(1, 1); |
| 331 scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); | 841 scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); |
| 332 | 842 |
| 333 SharedQuadState* shared_state = | 843 SharedQuadState* shared_state = |
| 334 CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); | 844 CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| 335 | 845 |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 383 pass_list.push_back(pass.Pass()); | 893 pass_list.push_back(pass.Pass()); |
| 384 | 894 |
| 385 EXPECT_TRUE(this->RunPixelTest( | 895 EXPECT_TRUE(this->RunPixelTest( |
| 386 &pass_list, | 896 &pass_list, |
| 387 base::FilePath(FILE_PATH_LITERAL("green_alpha.png")), | 897 base::FilePath(FILE_PATH_LITERAL("green_alpha.png")), |
| 388 FuzzyPixelOffByOneComparator(true))); | 898 FuzzyPixelOffByOneComparator(true))); |
| 389 } | 899 } |
| 390 | 900 |
| 391 class VideoGLRendererPixelTest : public GLRendererPixelTest { | 901 class VideoGLRendererPixelTest : public GLRendererPixelTest { |
| 392 protected: | 902 protected: |
| 393 void CreateTestYUVVideoDrawQuad_Striped(const SharedQuadState* shared_state, | |
| 394 media::VideoFrame::Format format, | |
| 395 bool is_transparent, | |
| 396 const gfx::RectF& tex_coord_rect, | |
| 397 RenderPass* render_pass) { | |
| 398 const gfx::Rect rect(this->device_viewport_size_); | |
| 399 | |
| 400 scoped_refptr<media::VideoFrame> video_frame = | |
| 401 media::VideoFrame::CreateFrame( | |
| 402 format, rect.size(), rect, rect.size(), base::TimeDelta()); | |
| 403 | |
| 404 // YUV values representing a striped pattern, for validating texture | |
| 405 // coordinates for sampling. | |
| 406 uint8_t y_value = 0; | |
| 407 uint8_t u_value = 0; | |
| 408 uint8_t v_value = 0; | |
| 409 for (int i = 0; i < video_frame->rows(media::VideoFrame::kYPlane); ++i) { | |
| 410 uint8_t* y_row = video_frame->data(media::VideoFrame::kYPlane) + | |
| 411 video_frame->stride(media::VideoFrame::kYPlane) * i; | |
| 412 for (int j = 0; j < video_frame->row_bytes(media::VideoFrame::kYPlane); | |
| 413 ++j) { | |
| 414 y_row[j] = (y_value += 1); | |
| 415 } | |
| 416 } | |
| 417 for (int i = 0; i < video_frame->rows(media::VideoFrame::kUPlane); ++i) { | |
| 418 uint8_t* u_row = video_frame->data(media::VideoFrame::kUPlane) + | |
| 419 video_frame->stride(media::VideoFrame::kUPlane) * i; | |
| 420 uint8_t* v_row = video_frame->data(media::VideoFrame::kVPlane) + | |
| 421 video_frame->stride(media::VideoFrame::kVPlane) * i; | |
| 422 for (int j = 0; j < video_frame->row_bytes(media::VideoFrame::kUPlane); | |
| 423 ++j) { | |
| 424 u_row[j] = (u_value += 3); | |
| 425 v_row[j] = (v_value += 5); | |
| 426 } | |
| 427 } | |
| 428 uint8 alpha_value = is_transparent ? 0 : 128; | |
| 429 CreateTestYUVVideoDrawQuad_FromVideoFrame( | |
| 430 shared_state, video_frame, alpha_value, tex_coord_rect, render_pass); | |
| 431 } | |
| 432 | |
| 433 void CreateTestYUVVideoDrawQuad_Solid(const SharedQuadState* shared_state, | |
| 434 media::VideoFrame::Format format, | |
| 435 bool is_transparent, | |
| 436 const gfx::RectF& tex_coord_rect, | |
| 437 uint8 y, | |
| 438 uint8 u, | |
| 439 uint8 v, | |
| 440 RenderPass* render_pass) { | |
| 441 const gfx::Rect rect(this->device_viewport_size_); | |
| 442 | |
| 443 scoped_refptr<media::VideoFrame> video_frame = | |
| 444 media::VideoFrame::CreateFrame( | |
| 445 format, rect.size(), rect, rect.size(), base::TimeDelta()); | |
| 446 | |
| 447 // YUV values of a solid, constant, color. Useful for testing that color | |
| 448 // space/color range are being handled properly. | |
| 449 memset(video_frame->data(media::VideoFrame::kYPlane), | |
| 450 y, | |
| 451 video_frame->stride(media::VideoFrame::kYPlane) * | |
| 452 video_frame->rows(media::VideoFrame::kYPlane)); | |
| 453 memset(video_frame->data(media::VideoFrame::kUPlane), | |
| 454 u, | |
| 455 video_frame->stride(media::VideoFrame::kUPlane) * | |
| 456 video_frame->rows(media::VideoFrame::kUPlane)); | |
| 457 memset(video_frame->data(media::VideoFrame::kVPlane), | |
| 458 v, | |
| 459 video_frame->stride(media::VideoFrame::kVPlane) * | |
| 460 video_frame->rows(media::VideoFrame::kVPlane)); | |
| 461 | |
| 462 uint8 alpha_value = is_transparent ? 0 : 128; | |
| 463 CreateTestYUVVideoDrawQuad_FromVideoFrame( | |
| 464 shared_state, video_frame, alpha_value, tex_coord_rect, render_pass); | |
| 465 } | |
| 466 | |
| 467 void CreateEdgeBleedPass(media::VideoFrame::Format format, | 903 void CreateEdgeBleedPass(media::VideoFrame::Format format, |
| 468 RenderPassList* pass_list) { | 904 RenderPassList* pass_list) { |
| 469 gfx::Rect rect(200, 200); | 905 gfx::Rect rect(200, 200); |
| 470 | 906 |
| 471 RenderPassId id(1, 1); | 907 RenderPassId id(1, 1); |
| 472 scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); | 908 scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); |
| 473 | 909 |
| 474 // Scale the video up so that bilinear filtering kicks in to sample more | 910 // Scale the video up so that bilinear filtering kicks in to sample more |
| 475 // than just nearest neighbor would. | 911 // than just nearest neighbor would. |
| 476 gfx::Transform scale_by_2; | 912 gfx::Transform scale_by_2; |
| 477 scale_by_2.Scale(2.f, 2.f); | 913 scale_by_2.Scale(2.f, 2.f); |
| 478 gfx::Rect half_rect(100, 100); | 914 gfx::Rect half_rect(100, 100); |
| 479 SharedQuadState* shared_state = | 915 SharedQuadState* shared_state = |
| 480 CreateTestSharedQuadState(scale_by_2, half_rect, pass.get()); | 916 CreateTestSharedQuadState(scale_by_2, half_rect, pass.get()); |
| 481 | 917 |
| 482 gfx::Size background_size(200, 200); | 918 gfx::Size background_size(200, 200); |
| 483 gfx::Rect green_rect(16, 20, 100, 100); | 919 gfx::Rect green_rect(16, 20, 100, 100); |
| 484 gfx::RectF tex_coord_rect( | 920 gfx::RectF tex_coord_rect( |
| 485 static_cast<float>(green_rect.x()) / background_size.width(), | 921 static_cast<float>(green_rect.x()) / background_size.width(), |
| 486 static_cast<float>(green_rect.y()) / background_size.height(), | 922 static_cast<float>(green_rect.y()) / background_size.height(), |
| 487 static_cast<float>(green_rect.width()) / background_size.width(), | 923 static_cast<float>(green_rect.width()) / background_size.width(), |
| 488 static_cast<float>(green_rect.height()) / background_size.height()); | 924 static_cast<float>(green_rect.height()) / background_size.height()); |
| 489 | 925 |
| 490 // YUV of (149,43,21) should be green (0,255,0) in RGB. | 926 // YUV of (149,43,21) should be green (0,255,0) in RGB. |
| 491 // Create a video frame that has a non-green background rect, with a | 927 // Create a video frame that has a non-green background rect, with a |
| 492 // green sub-rectangle that should be the only thing displayed in | 928 // green sub-rectangle that should be the only thing displayed in |
| 493 // the final image. Bleeding will appear on all four sides of the video | 929 // the final image. Bleeding will appear on all four sides of the video |
| 494 // if the tex coords are not clamped. | 930 // if the tex coords are not clamped. |
| 495 CreateTestYUVVideoDrawQuad_TwoColor(shared_state, format, false, | 931 CreateTestYUVVideoDrawQuad_TwoColor( |
| 496 tex_coord_rect, background_size, 0, 0, | 932 shared_state, format, false, tex_coord_rect, background_size, 0, 0, 0, |
| 497 0, green_rect, 149, 43, 21, pass.get()); | 933 green_rect, 149, 43, 21, pass.get(), video_resource_updater_.get(), |
| 934 resource_provider_.get()); |
| 498 pass_list->push_back(pass.Pass()); | 935 pass_list->push_back(pass.Pass()); |
| 499 } | 936 } |
| 500 | 937 |
| 501 // Creates a video frame of size background_size filled with yuv_background, | |
| 502 // and then draws a foreground rectangle in a different color on top of | |
| 503 // that. The foreground rectangle must have coordinates that are divisible | |
| 504 // by 2 because YUV is a block format. | |
| 505 void CreateTestYUVVideoDrawQuad_TwoColor(const SharedQuadState* shared_state, | |
| 506 media::VideoFrame::Format format, | |
| 507 bool is_transparent, | |
| 508 const gfx::RectF& tex_coord_rect, | |
| 509 const gfx::Size& background_size, | |
| 510 uint8 y_background, | |
| 511 uint8 u_background, | |
| 512 uint8 v_background, | |
| 513 const gfx::Rect& foreground_rect, | |
| 514 uint8 y_foreground, | |
| 515 uint8 u_foreground, | |
| 516 uint8 v_foreground, | |
| 517 RenderPass* render_pass) { | |
| 518 const gfx::Rect rect(background_size); | |
| 519 | |
| 520 scoped_refptr<media::VideoFrame> video_frame = | |
| 521 media::VideoFrame::CreateFrame(format, background_size, foreground_rect, | |
| 522 foreground_rect.size(), | |
| 523 base::TimeDelta()); | |
| 524 | |
| 525 int planes[] = {media::VideoFrame::kYPlane, | |
| 526 media::VideoFrame::kUPlane, | |
| 527 media::VideoFrame::kVPlane}; | |
| 528 uint8 yuv_background[] = {y_background, u_background, v_background}; | |
| 529 uint8 yuv_foreground[] = {y_foreground, u_foreground, v_foreground}; | |
| 530 int sample_size[] = {1, 2, 2}; | |
| 531 | |
| 532 for (int i = 0; i < 3; ++i) { | |
| 533 memset(video_frame->data(planes[i]), yuv_background[i], | |
| 534 video_frame->stride(planes[i]) * video_frame->rows(planes[i])); | |
| 535 } | |
| 536 | |
| 537 for (int i = 0; i < 3; ++i) { | |
| 538 // Since yuv encoding uses block encoding, widths have to be divisible | |
| 539 // by the sample size in order for this function to behave properly. | |
| 540 DCHECK_EQ(foreground_rect.x() % sample_size[i], 0); | |
| 541 DCHECK_EQ(foreground_rect.y() % sample_size[i], 0); | |
| 542 DCHECK_EQ(foreground_rect.width() % sample_size[i], 0); | |
| 543 DCHECK_EQ(foreground_rect.height() % sample_size[i], 0); | |
| 544 | |
| 545 gfx::Rect sample_rect(foreground_rect.x() / sample_size[i], | |
| 546 foreground_rect.y() / sample_size[i], | |
| 547 foreground_rect.width() / sample_size[i], | |
| 548 foreground_rect.height() / sample_size[i]); | |
| 549 for (int y = sample_rect.y(); y < sample_rect.bottom(); ++y) { | |
| 550 for (int x = sample_rect.x(); x < sample_rect.right(); ++x) { | |
| 551 size_t offset = y * video_frame->stride(planes[i]) + x; | |
| 552 video_frame->data(planes[i])[offset] = yuv_foreground[i]; | |
| 553 } | |
| 554 } | |
| 555 } | |
| 556 | |
| 557 uint8 alpha_value = 255; | |
| 558 CreateTestYUVVideoDrawQuad_FromVideoFrame( | |
| 559 shared_state, video_frame, alpha_value, tex_coord_rect, render_pass); | |
| 560 } | |
| 561 | |
| 562 void CreateTestYUVVideoDrawQuad_FromVideoFrame( | |
| 563 const SharedQuadState* shared_state, | |
| 564 scoped_refptr<media::VideoFrame> video_frame, | |
| 565 uint8 alpha_value, | |
| 566 const gfx::RectF& tex_coord_rect, | |
| 567 RenderPass* render_pass) { | |
| 568 const bool with_alpha = (video_frame->format() == media::VideoFrame::YV12A); | |
| 569 const YUVVideoDrawQuad::ColorSpace color_space = | |
| 570 (video_frame->format() == media::VideoFrame::YV12J | |
| 571 ? YUVVideoDrawQuad::JPEG | |
| 572 : YUVVideoDrawQuad::REC_601); | |
| 573 const gfx::Rect rect(shared_state->content_bounds); | |
| 574 const gfx::Rect opaque_rect(0, 0, 0, 0); | |
| 575 | |
| 576 if (with_alpha) | |
| 577 memset(video_frame->data(media::VideoFrame::kAPlane), alpha_value, | |
| 578 video_frame->stride(media::VideoFrame::kAPlane) * | |
| 579 video_frame->rows(media::VideoFrame::kAPlane)); | |
| 580 | |
| 581 VideoFrameExternalResources resources = | |
| 582 video_resource_updater_->CreateExternalResourcesFromVideoFrame( | |
| 583 video_frame); | |
| 584 | |
| 585 EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type); | |
| 586 EXPECT_EQ(media::VideoFrame::NumPlanes(video_frame->format()), | |
| 587 resources.mailboxes.size()); | |
| 588 EXPECT_EQ(media::VideoFrame::NumPlanes(video_frame->format()), | |
| 589 resources.release_callbacks.size()); | |
| 590 | |
| 591 ResourceProvider::ResourceId y_resource = | |
| 592 resource_provider_->CreateResourceFromTextureMailbox( | |
| 593 resources.mailboxes[media::VideoFrame::kYPlane], | |
| 594 SingleReleaseCallbackImpl::Create( | |
| 595 resources.release_callbacks[media::VideoFrame::kYPlane])); | |
| 596 ResourceProvider::ResourceId u_resource = | |
| 597 resource_provider_->CreateResourceFromTextureMailbox( | |
| 598 resources.mailboxes[media::VideoFrame::kUPlane], | |
| 599 SingleReleaseCallbackImpl::Create( | |
| 600 resources.release_callbacks[media::VideoFrame::kUPlane])); | |
| 601 ResourceProvider::ResourceId v_resource = | |
| 602 resource_provider_->CreateResourceFromTextureMailbox( | |
| 603 resources.mailboxes[media::VideoFrame::kVPlane], | |
| 604 SingleReleaseCallbackImpl::Create( | |
| 605 resources.release_callbacks[media::VideoFrame::kVPlane])); | |
| 606 ResourceProvider::ResourceId a_resource = 0; | |
| 607 if (with_alpha) { | |
| 608 a_resource = resource_provider_->CreateResourceFromTextureMailbox( | |
| 609 resources.mailboxes[media::VideoFrame::kAPlane], | |
| 610 SingleReleaseCallbackImpl::Create( | |
| 611 resources.release_callbacks[media::VideoFrame::kAPlane])); | |
| 612 } | |
| 613 | |
| 614 YUVVideoDrawQuad* yuv_quad = | |
| 615 render_pass->CreateAndAppendDrawQuad<YUVVideoDrawQuad>(); | |
| 616 yuv_quad->SetNew(shared_state, rect, opaque_rect, rect, tex_coord_rect, | |
| 617 video_frame->coded_size(), y_resource, u_resource, | |
| 618 v_resource, a_resource, color_space); | |
| 619 } | |
| 620 | |
| 621 void SetUp() override { | 938 void SetUp() override { |
| 622 GLRendererPixelTest::SetUp(); | 939 GLRendererPixelTest::SetUp(); |
| 623 video_resource_updater_.reset(new VideoResourceUpdater( | 940 video_resource_updater_.reset(new VideoResourceUpdater( |
| 624 output_surface_->context_provider(), resource_provider_.get())); | 941 output_surface_->context_provider(), resource_provider_.get())); |
| 625 } | 942 } |
| 626 | 943 |
| 627 private: | |
| 628 scoped_ptr<VideoResourceUpdater> video_resource_updater_; | 944 scoped_ptr<VideoResourceUpdater> video_resource_updater_; |
| 629 }; | 945 }; |
| 630 | 946 |
| 631 TEST_F(VideoGLRendererPixelTest, SimpleYUVRect) { | 947 TEST_F(VideoGLRendererPixelTest, SimpleYUVRect) { |
| 632 gfx::Rect rect(this->device_viewport_size_); | 948 gfx::Rect rect(this->device_viewport_size_); |
| 633 | 949 |
| 634 RenderPassId id(1, 1); | 950 RenderPassId id(1, 1); |
| 635 scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); | 951 scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); |
| 636 | 952 |
| 637 SharedQuadState* shared_state = | 953 SharedQuadState* shared_state = |
| 638 CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); | 954 CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| 639 | 955 |
| 640 CreateTestYUVVideoDrawQuad_Striped(shared_state, | 956 CreateTestYUVVideoDrawQuad_Striped(shared_state, media::VideoFrame::YV12, |
| 641 media::VideoFrame::YV12, | 957 false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), |
| 642 false, | 958 pass.get(), video_resource_updater_.get(), |
| 643 gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), | 959 rect, resource_provider_.get()); |
| 644 pass.get()); | |
| 645 | 960 |
| 646 RenderPassList pass_list; | 961 RenderPassList pass_list; |
| 647 pass_list.push_back(pass.Pass()); | 962 pass_list.push_back(pass.Pass()); |
| 648 | 963 |
| 649 EXPECT_TRUE( | 964 EXPECT_TRUE( |
| 650 this->RunPixelTest(&pass_list, | 965 this->RunPixelTest(&pass_list, |
| 651 base::FilePath(FILE_PATH_LITERAL("yuv_stripes.png")), | 966 base::FilePath(FILE_PATH_LITERAL("yuv_stripes.png")), |
| 652 FuzzyPixelOffByOneComparator(true))); | 967 FuzzyPixelOffByOneComparator(true))); |
| 653 } | 968 } |
| 654 | 969 |
| 655 TEST_F(VideoGLRendererPixelTest, OffsetYUVRect) { | 970 TEST_F(VideoGLRendererPixelTest, OffsetYUVRect) { |
| 656 gfx::Rect rect(this->device_viewport_size_); | 971 gfx::Rect rect(this->device_viewport_size_); |
| 657 | 972 |
| 658 RenderPassId id(1, 1); | 973 RenderPassId id(1, 1); |
| 659 scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); | 974 scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); |
| 660 | 975 |
| 661 SharedQuadState* shared_state = | 976 SharedQuadState* shared_state = |
| 662 CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); | 977 CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| 663 | 978 |
| 664 // Intentionally sets frame format to I420 for testing coverage. | 979 // Intentionally sets frame format to I420 for testing coverage. |
| 665 CreateTestYUVVideoDrawQuad_Striped(shared_state, | 980 CreateTestYUVVideoDrawQuad_Striped( |
| 666 media::VideoFrame::I420, | 981 shared_state, media::VideoFrame::I420, false, |
| 667 false, | 982 gfx::RectF(0.125f, 0.25f, 0.75f, 0.5f), pass.get(), |
| 668 gfx::RectF(0.125f, 0.25f, 0.75f, 0.5f), | 983 video_resource_updater_.get(), rect, resource_provider_.get()); |
| 669 pass.get()); | |
| 670 | 984 |
| 671 RenderPassList pass_list; | 985 RenderPassList pass_list; |
| 672 pass_list.push_back(pass.Pass()); | 986 pass_list.push_back(pass.Pass()); |
| 673 | 987 |
| 674 EXPECT_TRUE(this->RunPixelTest( | 988 EXPECT_TRUE(this->RunPixelTest( |
| 675 &pass_list, | 989 &pass_list, |
| 676 base::FilePath(FILE_PATH_LITERAL("yuv_stripes_offset.png")), | 990 base::FilePath(FILE_PATH_LITERAL("yuv_stripes_offset.png")), |
| 677 FuzzyPixelOffByOneComparator(true))); | 991 FuzzyPixelOffByOneComparator(true))); |
| 678 } | 992 } |
| 679 | 993 |
| 680 TEST_F(VideoGLRendererPixelTest, SimpleYUVRectBlack) { | 994 TEST_F(VideoGLRendererPixelTest, SimpleYUVRectBlack) { |
| 681 gfx::Rect rect(this->device_viewport_size_); | 995 gfx::Rect rect(this->device_viewport_size_); |
| 682 | 996 |
| 683 RenderPassId id(1, 1); | 997 RenderPassId id(1, 1); |
| 684 scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); | 998 scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); |
| 685 | 999 |
| 686 SharedQuadState* shared_state = | 1000 SharedQuadState* shared_state = |
| 687 CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); | 1001 CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| 688 | 1002 |
| 689 // In MPEG color range YUV values of (15,128,128) should produce black. | 1003 // In MPEG color range YUV values of (15,128,128) should produce black. |
| 690 CreateTestYUVVideoDrawQuad_Solid(shared_state, | 1004 CreateTestYUVVideoDrawQuad_Solid( |
| 691 media::VideoFrame::YV12, | 1005 shared_state, media::VideoFrame::YV12, false, |
| 692 false, | 1006 gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 15, 128, 128, pass.get(), |
| 693 gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), | 1007 video_resource_updater_.get(), rect, resource_provider_.get()); |
| 694 15, | |
| 695 128, | |
| 696 128, | |
| 697 pass.get()); | |
| 698 | 1008 |
| 699 RenderPassList pass_list; | 1009 RenderPassList pass_list; |
| 700 pass_list.push_back(pass.Pass()); | 1010 pass_list.push_back(pass.Pass()); |
| 701 | 1011 |
| 702 // If we didn't get black out of the YUV values above, then we probably have a | 1012 // If we didn't get black out of the YUV values above, then we probably have a |
| 703 // color range issue. | 1013 // color range issue. |
| 704 EXPECT_TRUE(this->RunPixelTest(&pass_list, | 1014 EXPECT_TRUE(this->RunPixelTest(&pass_list, |
| 705 base::FilePath(FILE_PATH_LITERAL("black.png")), | 1015 base::FilePath(FILE_PATH_LITERAL("black.png")), |
| 706 FuzzyPixelOffByOneComparator(true))); | 1016 FuzzyPixelOffByOneComparator(true))); |
| 707 } | 1017 } |
| 708 | 1018 |
| 709 TEST_F(VideoGLRendererPixelTest, SimpleYUVJRect) { | 1019 TEST_F(VideoGLRendererPixelTest, SimpleYUVJRect) { |
| 710 gfx::Rect rect(this->device_viewport_size_); | 1020 gfx::Rect rect(this->device_viewport_size_); |
| 711 | 1021 |
| 712 RenderPassId id(1, 1); | 1022 RenderPassId id(1, 1); |
| 713 scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); | 1023 scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); |
| 714 | 1024 |
| 715 SharedQuadState* shared_state = | 1025 SharedQuadState* shared_state = |
| 716 CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); | 1026 CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| 717 | 1027 |
| 718 // YUV of (149,43,21) should be green (0,255,0) in RGB. | 1028 // YUV of (149,43,21) should be green (0,255,0) in RGB. |
| 719 CreateTestYUVVideoDrawQuad_Solid(shared_state, | 1029 CreateTestYUVVideoDrawQuad_Solid( |
| 720 media::VideoFrame::YV12J, | 1030 shared_state, media::VideoFrame::YV12J, false, |
| 721 false, | 1031 gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 149, 43, 21, pass.get(), |
| 722 gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), | 1032 video_resource_updater_.get(), rect, resource_provider_.get()); |
| 723 149, | |
| 724 43, | |
| 725 21, | |
| 726 pass.get()); | |
| 727 | 1033 |
| 728 RenderPassList pass_list; | 1034 RenderPassList pass_list; |
| 729 pass_list.push_back(pass.Pass()); | 1035 pass_list.push_back(pass.Pass()); |
| 730 | 1036 |
| 731 EXPECT_TRUE(this->RunPixelTest(&pass_list, | 1037 EXPECT_TRUE(this->RunPixelTest(&pass_list, |
| 732 base::FilePath(FILE_PATH_LITERAL("green.png")), | 1038 base::FilePath(FILE_PATH_LITERAL("green.png")), |
| 733 FuzzyPixelOffByOneComparator(true))); | 1039 FuzzyPixelOffByOneComparator(true))); |
| 734 } | 1040 } |
| 735 | 1041 |
| 736 // Test that a YUV video doesn't bleed outside of its tex coords when the | 1042 // Test that a YUV video doesn't bleed outside of its tex coords when the |
| (...skipping 17 matching lines...) Expand all Loading... |
| 754 TEST_F(VideoGLRendererPixelTest, SimpleYUVJRectGrey) { | 1060 TEST_F(VideoGLRendererPixelTest, SimpleYUVJRectGrey) { |
| 755 gfx::Rect rect(this->device_viewport_size_); | 1061 gfx::Rect rect(this->device_viewport_size_); |
| 756 | 1062 |
| 757 RenderPassId id(1, 1); | 1063 RenderPassId id(1, 1); |
| 758 scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); | 1064 scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); |
| 759 | 1065 |
| 760 SharedQuadState* shared_state = | 1066 SharedQuadState* shared_state = |
| 761 CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); | 1067 CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| 762 | 1068 |
| 763 // Dark grey in JPEG color range (in MPEG, this is black). | 1069 // Dark grey in JPEG color range (in MPEG, this is black). |
| 764 CreateTestYUVVideoDrawQuad_Solid(shared_state, | 1070 CreateTestYUVVideoDrawQuad_Solid( |
| 765 media::VideoFrame::YV12J, | 1071 shared_state, media::VideoFrame::YV12J, false, |
| 766 false, | 1072 gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 15, 128, 128, pass.get(), |
| 767 gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), | 1073 video_resource_updater_.get(), rect, resource_provider_.get()); |
| 768 15, | |
| 769 128, | |
| 770 128, | |
| 771 pass.get()); | |
| 772 | 1074 |
| 773 RenderPassList pass_list; | 1075 RenderPassList pass_list; |
| 774 pass_list.push_back(pass.Pass()); | 1076 pass_list.push_back(pass.Pass()); |
| 775 | 1077 |
| 776 EXPECT_TRUE( | 1078 EXPECT_TRUE( |
| 777 this->RunPixelTest(&pass_list, | 1079 this->RunPixelTest(&pass_list, |
| 778 base::FilePath(FILE_PATH_LITERAL("dark_grey.png")), | 1080 base::FilePath(FILE_PATH_LITERAL("dark_grey.png")), |
| 779 FuzzyPixelOffByOneComparator(true))); | 1081 FuzzyPixelOffByOneComparator(true))); |
| 780 } | 1082 } |
| 781 | 1083 |
| 782 TEST_F(VideoGLRendererPixelTest, SimpleYUVARect) { | 1084 TEST_F(VideoGLRendererPixelTest, SimpleYUVARect) { |
| 783 gfx::Rect rect(this->device_viewport_size_); | 1085 gfx::Rect rect(this->device_viewport_size_); |
| 784 | 1086 |
| 785 RenderPassId id(1, 1); | 1087 RenderPassId id(1, 1); |
| 786 scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); | 1088 scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); |
| 787 | 1089 |
| 788 SharedQuadState* shared_state = | 1090 SharedQuadState* shared_state = |
| 789 CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); | 1091 CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| 790 | 1092 |
| 791 CreateTestYUVVideoDrawQuad_Striped(shared_state, | 1093 CreateTestYUVVideoDrawQuad_Striped(shared_state, media::VideoFrame::YV12A, |
| 792 media::VideoFrame::YV12A, | 1094 false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), |
| 793 false, | 1095 pass.get(), video_resource_updater_.get(), |
| 794 gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), | 1096 rect, resource_provider_.get()); |
| 795 pass.get()); | |
| 796 | 1097 |
| 797 SolidColorDrawQuad* color_quad = | 1098 SolidColorDrawQuad* color_quad = |
| 798 pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); | 1099 pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| 799 color_quad->SetNew(shared_state, rect, rect, SK_ColorWHITE, false); | 1100 color_quad->SetNew(shared_state, rect, rect, SK_ColorWHITE, false); |
| 800 | 1101 |
| 801 RenderPassList pass_list; | 1102 RenderPassList pass_list; |
| 802 pass_list.push_back(pass.Pass()); | 1103 pass_list.push_back(pass.Pass()); |
| 803 | 1104 |
| 804 EXPECT_TRUE(this->RunPixelTest( | 1105 EXPECT_TRUE(this->RunPixelTest( |
| 805 &pass_list, | 1106 &pass_list, |
| 806 base::FilePath(FILE_PATH_LITERAL("yuv_stripes_alpha.png")), | 1107 base::FilePath(FILE_PATH_LITERAL("yuv_stripes_alpha.png")), |
| 807 FuzzyPixelOffByOneComparator(true))); | 1108 FuzzyPixelOffByOneComparator(true))); |
| 808 } | 1109 } |
| 809 | 1110 |
| 810 TEST_F(VideoGLRendererPixelTest, FullyTransparentYUVARect) { | 1111 TEST_F(VideoGLRendererPixelTest, FullyTransparentYUVARect) { |
| 811 gfx::Rect rect(this->device_viewport_size_); | 1112 gfx::Rect rect(this->device_viewport_size_); |
| 812 | 1113 |
| 813 RenderPassId id(1, 1); | 1114 RenderPassId id(1, 1); |
| 814 scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); | 1115 scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); |
| 815 | 1116 |
| 816 SharedQuadState* shared_state = | 1117 SharedQuadState* shared_state = |
| 817 CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); | 1118 CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| 818 | 1119 |
| 819 CreateTestYUVVideoDrawQuad_Striped(shared_state, | 1120 CreateTestYUVVideoDrawQuad_Striped(shared_state, media::VideoFrame::YV12A, |
| 820 media::VideoFrame::YV12A, | 1121 true, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), |
| 821 true, | 1122 pass.get(), video_resource_updater_.get(), |
| 822 gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), | 1123 rect, resource_provider_.get()); |
| 823 pass.get()); | |
| 824 | 1124 |
| 825 SolidColorDrawQuad* color_quad = | 1125 SolidColorDrawQuad* color_quad = |
| 826 pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); | 1126 pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| 827 color_quad->SetNew(shared_state, rect, rect, SK_ColorBLACK, false); | 1127 color_quad->SetNew(shared_state, rect, rect, SK_ColorBLACK, false); |
| 828 | 1128 |
| 829 RenderPassList pass_list; | 1129 RenderPassList pass_list; |
| 830 pass_list.push_back(pass.Pass()); | 1130 pass_list.push_back(pass.Pass()); |
| 831 | 1131 |
| 832 EXPECT_TRUE(this->RunPixelTest( | 1132 EXPECT_TRUE(this->RunPixelTest( |
| 833 &pass_list, | 1133 &pass_list, |
| (...skipping 1656 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2490 EXPECT_TRUE(this->RunPixelTest( | 2790 EXPECT_TRUE(this->RunPixelTest( |
| 2491 &pass_list, | 2791 &pass_list, |
| 2492 base::FilePath(FILE_PATH_LITERAL("wrap_mode_repeat.png")), | 2792 base::FilePath(FILE_PATH_LITERAL("wrap_mode_repeat.png")), |
| 2493 FuzzyPixelOffByOneComparator(true))); | 2793 FuzzyPixelOffByOneComparator(true))); |
| 2494 } | 2794 } |
| 2495 | 2795 |
| 2496 #endif // !defined(OS_ANDROID) | 2796 #endif // !defined(OS_ANDROID) |
| 2497 | 2797 |
| 2498 } // namespace | 2798 } // namespace |
| 2499 } // namespace cc | 2799 } // namespace cc |
| OLD | NEW |