OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "cc/output/direct_renderer.h" |
| 6 |
| 7 #include <utility> |
| 8 #include <vector> |
| 9 |
| 10 #include "base/containers/hash_tables.h" |
| 11 #include "base/containers/scoped_ptr_hash_map.h" |
| 12 #include "base/metrics/histogram.h" |
| 13 #include "base/trace_event/trace_event.h" |
| 14 #include "cc/base/math_util.h" |
| 15 #include "cc/output/bsp_tree.h" |
| 16 #include "cc/output/bsp_walk_action.h" |
| 17 #include "cc/output/copy_output_request.h" |
| 18 #include "cc/quads/draw_quad.h" |
| 19 #include "ui/gfx/geometry/rect_conversions.h" |
| 20 #include "ui/gfx/transform.h" |
| 21 |
| 22 static gfx::Transform OrthoProjectionMatrix(float left, |
| 23 float right, |
| 24 float bottom, |
| 25 float top) { |
| 26 // Use the standard formula to map the clipping frustum to the cube from |
| 27 // [-1, -1, -1] to [1, 1, 1]. |
| 28 float delta_x = right - left; |
| 29 float delta_y = top - bottom; |
| 30 gfx::Transform proj; |
| 31 if (!delta_x || !delta_y) |
| 32 return proj; |
| 33 proj.matrix().set(0, 0, 2.0f / delta_x); |
| 34 proj.matrix().set(0, 3, -(right + left) / delta_x); |
| 35 proj.matrix().set(1, 1, 2.0f / delta_y); |
| 36 proj.matrix().set(1, 3, -(top + bottom) / delta_y); |
| 37 |
| 38 // Z component of vertices is always set to zero as we don't use the depth |
| 39 // buffer while drawing. |
| 40 proj.matrix().set(2, 2, 0); |
| 41 |
| 42 return proj; |
| 43 } |
| 44 |
| 45 static gfx::Transform window_matrix(int x, int y, int width, int height) { |
| 46 gfx::Transform canvas; |
| 47 |
| 48 // Map to window position and scale up to pixel coordinates. |
| 49 canvas.Translate3d(x, y, 0); |
| 50 canvas.Scale3d(width, height, 0); |
| 51 |
| 52 // Map from ([-1, -1] to [1, 1]) -> ([0, 0] to [1, 1]) |
| 53 canvas.Translate3d(0.5, 0.5, 0.5); |
| 54 canvas.Scale3d(0.5, 0.5, 0.5); |
| 55 |
| 56 return canvas; |
| 57 } |
| 58 |
| 59 namespace cc { |
| 60 |
| 61 DirectRenderer::DrawingFrame::DrawingFrame() |
| 62 : root_render_pass(NULL), current_render_pass(NULL), current_texture(NULL) { |
| 63 } |
| 64 |
| 65 DirectRenderer::DrawingFrame::~DrawingFrame() {} |
| 66 |
| 67 // |
| 68 // static |
| 69 gfx::RectF DirectRenderer::QuadVertexRect() { |
| 70 return gfx::RectF(-0.5f, -0.5f, 1.f, 1.f); |
| 71 } |
| 72 |
| 73 // static |
| 74 void DirectRenderer::QuadRectTransform(gfx::Transform* quad_rect_transform, |
| 75 const gfx::Transform& quad_transform, |
| 76 const gfx::RectF& quad_rect) { |
| 77 *quad_rect_transform = quad_transform; |
| 78 quad_rect_transform->Translate(0.5 * quad_rect.width() + quad_rect.x(), |
| 79 0.5 * quad_rect.height() + quad_rect.y()); |
| 80 quad_rect_transform->Scale(quad_rect.width(), quad_rect.height()); |
| 81 } |
| 82 |
| 83 void DirectRenderer::InitializeViewport(DrawingFrame* frame, |
| 84 const gfx::Rect& draw_rect, |
| 85 const gfx::Rect& viewport_rect, |
| 86 const gfx::Size& surface_size) { |
| 87 DCHECK_GE(viewport_rect.x(), 0); |
| 88 DCHECK_GE(viewport_rect.y(), 0); |
| 89 DCHECK_LE(viewport_rect.right(), surface_size.width()); |
| 90 DCHECK_LE(viewport_rect.bottom(), surface_size.height()); |
| 91 bool flip_y = FlippedFramebuffer(frame); |
| 92 if (flip_y) { |
| 93 frame->projection_matrix = OrthoProjectionMatrix(draw_rect.x(), |
| 94 draw_rect.right(), |
| 95 draw_rect.bottom(), |
| 96 draw_rect.y()); |
| 97 } else { |
| 98 frame->projection_matrix = OrthoProjectionMatrix(draw_rect.x(), |
| 99 draw_rect.right(), |
| 100 draw_rect.y(), |
| 101 draw_rect.bottom()); |
| 102 } |
| 103 |
| 104 gfx::Rect window_rect = viewport_rect; |
| 105 if (flip_y) |
| 106 window_rect.set_y(surface_size.height() - viewport_rect.bottom()); |
| 107 frame->window_matrix = window_matrix(window_rect.x(), |
| 108 window_rect.y(), |
| 109 window_rect.width(), |
| 110 window_rect.height()); |
| 111 SetDrawViewport(window_rect); |
| 112 |
| 113 current_draw_rect_ = draw_rect; |
| 114 current_viewport_rect_ = viewport_rect; |
| 115 current_surface_size_ = surface_size; |
| 116 } |
| 117 |
| 118 gfx::Rect DirectRenderer::MoveFromDrawToWindowSpace( |
| 119 const DrawingFrame* frame, |
| 120 const gfx::Rect& draw_rect) const { |
| 121 gfx::Rect window_rect = draw_rect; |
| 122 window_rect -= current_draw_rect_.OffsetFromOrigin(); |
| 123 window_rect += current_viewport_rect_.OffsetFromOrigin(); |
| 124 if (FlippedFramebuffer(frame)) |
| 125 window_rect.set_y(current_surface_size_.height() - window_rect.bottom()); |
| 126 return window_rect; |
| 127 } |
| 128 |
| 129 DirectRenderer::DirectRenderer(RendererClient* client, |
| 130 const RendererSettings* settings, |
| 131 OutputSurface* output_surface, |
| 132 ResourceProvider* resource_provider) |
| 133 : Renderer(client, settings), |
| 134 output_surface_(output_surface), |
| 135 resource_provider_(resource_provider), |
| 136 overlay_processor_( |
| 137 new OverlayProcessor(output_surface, resource_provider)) { |
| 138 overlay_processor_->Initialize(); |
| 139 } |
| 140 |
| 141 DirectRenderer::~DirectRenderer() {} |
| 142 |
| 143 void DirectRenderer::SetEnlargePassTextureAmountForTesting( |
| 144 const gfx::Vector2d& amount) { |
| 145 enlarge_pass_texture_amount_ = amount; |
| 146 } |
| 147 |
| 148 void DirectRenderer::DecideRenderPassAllocationsForFrame( |
| 149 const RenderPassList& render_passes_in_draw_order) { |
| 150 if (!resource_provider_) |
| 151 return; |
| 152 |
| 153 base::hash_map<RenderPassId, gfx::Size> render_passes_in_frame; |
| 154 for (size_t i = 0; i < render_passes_in_draw_order.size(); ++i) |
| 155 render_passes_in_frame.insert(std::pair<RenderPassId, gfx::Size>( |
| 156 render_passes_in_draw_order[i]->id, |
| 157 RenderPassTextureSize(render_passes_in_draw_order[i]))); |
| 158 |
| 159 std::vector<RenderPassId> passes_to_delete; |
| 160 base::ScopedPtrHashMap<RenderPassId, scoped_ptr<ScopedResource>>::const_iterat
or |
| 161 pass_iter; |
| 162 for (pass_iter = render_pass_textures_.begin(); |
| 163 pass_iter != render_pass_textures_.end(); |
| 164 ++pass_iter) { |
| 165 base::hash_map<RenderPassId, gfx::Size>::const_iterator it = |
| 166 render_passes_in_frame.find(pass_iter->first); |
| 167 if (it == render_passes_in_frame.end()) { |
| 168 passes_to_delete.push_back(pass_iter->first); |
| 169 continue; |
| 170 } |
| 171 |
| 172 gfx::Size required_size = it->second; |
| 173 ScopedResource* texture = pass_iter->second; |
| 174 DCHECK(texture); |
| 175 |
| 176 bool size_appropriate = texture->size().width() >= required_size.width() && |
| 177 texture->size().height() >= required_size.height(); |
| 178 if (texture->id() && !size_appropriate) |
| 179 texture->Free(); |
| 180 } |
| 181 |
| 182 // Delete RenderPass textures from the previous frame that will not be used |
| 183 // again. |
| 184 for (size_t i = 0; i < passes_to_delete.size(); ++i) |
| 185 render_pass_textures_.erase(passes_to_delete[i]); |
| 186 |
| 187 for (size_t i = 0; i < render_passes_in_draw_order.size(); ++i) { |
| 188 if (!render_pass_textures_.contains(render_passes_in_draw_order[i]->id)) { |
| 189 scoped_ptr<ScopedResource> texture = |
| 190 ScopedResource::Create(resource_provider_); |
| 191 render_pass_textures_.set(render_passes_in_draw_order[i]->id, |
| 192 texture.Pass()); |
| 193 } |
| 194 } |
| 195 } |
| 196 |
| 197 void DirectRenderer::DrawFrame(RenderPassList* render_passes_in_draw_order, |
| 198 float device_scale_factor, |
| 199 const gfx::Rect& device_viewport_rect, |
| 200 const gfx::Rect& device_clip_rect, |
| 201 bool disable_picture_quad_image_filtering) { |
| 202 TRACE_EVENT0("cc", "DirectRenderer::DrawFrame"); |
| 203 UMA_HISTOGRAM_COUNTS("Renderer4.renderPassCount", |
| 204 render_passes_in_draw_order->size()); |
| 205 |
| 206 const RenderPass* root_render_pass = render_passes_in_draw_order->back(); |
| 207 DCHECK(root_render_pass); |
| 208 |
| 209 DrawingFrame frame; |
| 210 frame.render_passes_in_draw_order = render_passes_in_draw_order; |
| 211 frame.root_render_pass = root_render_pass; |
| 212 frame.root_damage_rect = Capabilities().using_partial_swap |
| 213 ? root_render_pass->damage_rect |
| 214 : root_render_pass->output_rect; |
| 215 frame.root_damage_rect.Intersect(gfx::Rect(device_viewport_rect.size())); |
| 216 frame.device_viewport_rect = device_viewport_rect; |
| 217 frame.device_clip_rect = device_clip_rect; |
| 218 frame.disable_picture_quad_image_filtering = |
| 219 disable_picture_quad_image_filtering; |
| 220 |
| 221 overlay_processor_->ProcessForOverlays(render_passes_in_draw_order, |
| 222 &frame.overlay_list); |
| 223 |
| 224 EnsureBackbuffer(); |
| 225 |
| 226 // Only reshape when we know we are going to draw. Otherwise, the reshape |
| 227 // can leave the window at the wrong size if we never draw and the proper |
| 228 // viewport size is never set. |
| 229 output_surface_->Reshape(device_viewport_rect.size(), device_scale_factor); |
| 230 |
| 231 BeginDrawingFrame(&frame); |
| 232 for (size_t i = 0; i < render_passes_in_draw_order->size(); ++i) { |
| 233 RenderPass* pass = render_passes_in_draw_order->at(i); |
| 234 DrawRenderPass(&frame, pass); |
| 235 |
| 236 for (ScopedPtrVector<CopyOutputRequest>::iterator it = |
| 237 pass->copy_requests.begin(); |
| 238 it != pass->copy_requests.end(); |
| 239 ++it) { |
| 240 if (it != pass->copy_requests.begin()) { |
| 241 // Doing a readback is destructive of our state on Mac, so make sure |
| 242 // we restore the state between readbacks. http://crbug.com/99393. |
| 243 UseRenderPass(&frame, pass); |
| 244 } |
| 245 CopyCurrentRenderPassToBitmap(&frame, pass->copy_requests.take(it)); |
| 246 } |
| 247 } |
| 248 FinishDrawingFrame(&frame); |
| 249 |
| 250 render_passes_in_draw_order->clear(); |
| 251 } |
| 252 |
| 253 gfx::Rect DirectRenderer::ComputeScissorRectForRenderPass( |
| 254 const DrawingFrame* frame) { |
| 255 gfx::Rect render_pass_scissor = frame->current_render_pass->output_rect; |
| 256 |
| 257 if (frame->root_damage_rect == frame->root_render_pass->output_rect || |
| 258 !frame->current_render_pass->copy_requests.empty()) |
| 259 return render_pass_scissor; |
| 260 |
| 261 gfx::Transform inverse_transform(gfx::Transform::kSkipInitialization); |
| 262 if (frame->current_render_pass->transform_to_root_target.GetInverse( |
| 263 &inverse_transform)) { |
| 264 // Only intersect inverse-projected damage if the transform is invertible. |
| 265 gfx::Rect damage_rect_in_render_pass_space = |
| 266 MathUtil::ProjectEnclosingClippedRect(inverse_transform, |
| 267 frame->root_damage_rect); |
| 268 render_pass_scissor.Intersect(damage_rect_in_render_pass_space); |
| 269 } |
| 270 |
| 271 return render_pass_scissor; |
| 272 } |
| 273 |
| 274 bool DirectRenderer::NeedDeviceClip(const DrawingFrame* frame) const { |
| 275 if (frame->current_render_pass != frame->root_render_pass) |
| 276 return false; |
| 277 |
| 278 return !frame->device_clip_rect.Contains(frame->device_viewport_rect); |
| 279 } |
| 280 |
| 281 gfx::Rect DirectRenderer::DeviceClipRectInDrawSpace( |
| 282 const DrawingFrame* frame) const { |
| 283 gfx::Rect device_clip_rect = frame->device_clip_rect; |
| 284 device_clip_rect -= current_viewport_rect_.OffsetFromOrigin(); |
| 285 device_clip_rect += current_draw_rect_.OffsetFromOrigin(); |
| 286 return device_clip_rect; |
| 287 } |
| 288 |
| 289 gfx::Rect DirectRenderer::DeviceViewportRectInDrawSpace( |
| 290 const DrawingFrame* frame) const { |
| 291 gfx::Rect device_viewport_rect = frame->device_viewport_rect; |
| 292 device_viewport_rect -= current_viewport_rect_.OffsetFromOrigin(); |
| 293 device_viewport_rect += current_draw_rect_.OffsetFromOrigin(); |
| 294 return device_viewport_rect; |
| 295 } |
| 296 |
| 297 gfx::Rect DirectRenderer::OutputSurfaceRectInDrawSpace( |
| 298 const DrawingFrame* frame) const { |
| 299 if (frame->current_render_pass == frame->root_render_pass) { |
| 300 gfx::Rect output_surface_rect(output_surface_->SurfaceSize()); |
| 301 output_surface_rect -= current_viewport_rect_.OffsetFromOrigin(); |
| 302 output_surface_rect += current_draw_rect_.OffsetFromOrigin(); |
| 303 return output_surface_rect; |
| 304 } else { |
| 305 return frame->current_render_pass->output_rect; |
| 306 } |
| 307 } |
| 308 |
| 309 bool DirectRenderer::ShouldSkipQuad(const DrawQuad& quad, |
| 310 const gfx::Rect& render_pass_scissor) { |
| 311 if (render_pass_scissor.IsEmpty()) |
| 312 return true; |
| 313 |
| 314 if (quad.isClipped()) { |
| 315 gfx::Rect r = quad.clipRect(); |
| 316 r.Intersect(render_pass_scissor); |
| 317 return r.IsEmpty(); |
| 318 } |
| 319 |
| 320 return false; |
| 321 } |
| 322 |
| 323 void DirectRenderer::SetScissorStateForQuad( |
| 324 const DrawingFrame* frame, |
| 325 const DrawQuad& quad, |
| 326 const gfx::Rect& render_pass_scissor, |
| 327 bool use_render_pass_scissor) { |
| 328 if (use_render_pass_scissor) { |
| 329 gfx::Rect quad_scissor_rect = render_pass_scissor; |
| 330 if (quad.isClipped()) |
| 331 quad_scissor_rect.Intersect(quad.clipRect()); |
| 332 SetScissorTestRectInDrawSpace(frame, quad_scissor_rect); |
| 333 return; |
| 334 } else if (quad.isClipped()) { |
| 335 SetScissorTestRectInDrawSpace(frame, quad.clipRect()); |
| 336 return; |
| 337 } |
| 338 |
| 339 EnsureScissorTestDisabled(); |
| 340 } |
| 341 |
| 342 void DirectRenderer::SetScissorTestRectInDrawSpace( |
| 343 const DrawingFrame* frame, |
| 344 const gfx::Rect& draw_space_rect) { |
| 345 gfx::Rect window_space_rect = |
| 346 MoveFromDrawToWindowSpace(frame, draw_space_rect); |
| 347 SetScissorTestRect(window_space_rect); |
| 348 } |
| 349 |
| 350 void DirectRenderer::FinishDrawingQuadList() {} |
| 351 |
| 352 void DirectRenderer::DoDrawPolygon(const DrawPolygon& poly, |
| 353 DrawingFrame* frame, |
| 354 const gfx::Rect& render_pass_scissor, |
| 355 bool use_render_pass_scissor) { |
| 356 SetScissorStateForQuad(frame, *poly.original_ref(), render_pass_scissor, |
| 357 use_render_pass_scissor); |
| 358 |
| 359 // If the poly has not been split, then it is just a normal DrawQuad, |
| 360 // and we should save any extra processing that would have to be done. |
| 361 if (!poly.is_split()) { |
| 362 DoDrawQuad(frame, poly.original_ref(), NULL); |
| 363 return; |
| 364 } |
| 365 |
| 366 std::vector<gfx::QuadF> quads; |
| 367 poly.ToQuads2D(&quads); |
| 368 for (size_t i = 0; i < quads.size(); ++i) { |
| 369 DoDrawQuad(frame, poly.original_ref(), &quads[i]); |
| 370 } |
| 371 } |
| 372 |
| 373 void DirectRenderer::FlushPolygons(ScopedPtrDeque<DrawPolygon>* poly_list, |
| 374 DrawingFrame* frame, |
| 375 const gfx::Rect& render_pass_scissor, |
| 376 bool use_render_pass_scissor) { |
| 377 if (poly_list->empty()) { |
| 378 return; |
| 379 } |
| 380 |
| 381 BspTree bsp_tree(poly_list); |
| 382 BspWalkActionDrawPolygon action_handler(this, frame, render_pass_scissor, |
| 383 use_render_pass_scissor); |
| 384 bsp_tree.TraverseWithActionHandler(&action_handler); |
| 385 DCHECK(poly_list->empty()); |
| 386 } |
| 387 |
| 388 void DirectRenderer::DrawRenderPass(DrawingFrame* frame, |
| 389 const RenderPass* render_pass) { |
| 390 TRACE_EVENT0("cc", "DirectRenderer::DrawRenderPass"); |
| 391 if (!UseRenderPass(frame, render_pass)) |
| 392 return; |
| 393 |
| 394 const gfx::Rect surface_rect_in_draw_space = |
| 395 OutputSurfaceRectInDrawSpace(frame); |
| 396 gfx::Rect render_pass_scissor_in_draw_space = surface_rect_in_draw_space; |
| 397 |
| 398 if (frame->current_render_pass == frame->root_render_pass) { |
| 399 render_pass_scissor_in_draw_space.Intersect( |
| 400 DeviceViewportRectInDrawSpace(frame)); |
| 401 } |
| 402 |
| 403 if (Capabilities().using_partial_swap) { |
| 404 render_pass_scissor_in_draw_space.Intersect( |
| 405 ComputeScissorRectForRenderPass(frame)); |
| 406 } |
| 407 |
| 408 if (NeedDeviceClip(frame)) { |
| 409 render_pass_scissor_in_draw_space.Intersect( |
| 410 DeviceClipRectInDrawSpace(frame)); |
| 411 } |
| 412 |
| 413 bool render_pass_is_clipped = |
| 414 !render_pass_scissor_in_draw_space.Contains(surface_rect_in_draw_space); |
| 415 bool is_root_render_pass = |
| 416 frame->current_render_pass == frame->root_render_pass; |
| 417 bool has_external_stencil_test = |
| 418 is_root_render_pass && output_surface_->HasExternalStencilTest(); |
| 419 bool should_clear_surface = |
| 420 !has_external_stencil_test && |
| 421 (!is_root_render_pass || settings_->should_clear_root_render_pass); |
| 422 |
| 423 // If |has_external_stencil_test| we can't discard or clear. Make sure we |
| 424 // don't need to. |
| 425 DCHECK_IMPLIES(has_external_stencil_test, |
| 426 !frame->current_render_pass->has_transparent_background); |
| 427 |
| 428 SurfaceInitializationMode mode; |
| 429 if (should_clear_surface && render_pass_is_clipped) { |
| 430 mode = SURFACE_INITIALIZATION_MODE_SCISSORED_CLEAR; |
| 431 } else if (should_clear_surface) { |
| 432 mode = SURFACE_INITIALIZATION_MODE_FULL_SURFACE_CLEAR; |
| 433 } else { |
| 434 mode = SURFACE_INITIALIZATION_MODE_PRESERVE; |
| 435 } |
| 436 |
| 437 PrepareSurfaceForPass( |
| 438 frame, mode, |
| 439 MoveFromDrawToWindowSpace(frame, render_pass_scissor_in_draw_space)); |
| 440 |
| 441 const QuadList& quad_list = render_pass->quad_list; |
| 442 ScopedPtrDeque<DrawPolygon> poly_list; |
| 443 |
| 444 int next_polygon_id = 0; |
| 445 int last_sorting_context_id = 0; |
| 446 for (auto it = quad_list.BackToFrontBegin(); it != quad_list.BackToFrontEnd(); |
| 447 ++it) { |
| 448 const DrawQuad& quad = **it; |
| 449 gfx::QuadF send_quad(quad.visible_rect); |
| 450 |
| 451 if (render_pass_is_clipped && |
| 452 ShouldSkipQuad(quad, render_pass_scissor_in_draw_space)) { |
| 453 continue; |
| 454 } |
| 455 |
| 456 if (last_sorting_context_id != quad.shared_quad_state->sorting_context_id) { |
| 457 last_sorting_context_id = quad.shared_quad_state->sorting_context_id; |
| 458 FlushPolygons(&poly_list, frame, render_pass_scissor_in_draw_space, |
| 459 render_pass_is_clipped); |
| 460 } |
| 461 |
| 462 // This layer is in a 3D sorting context so we add it to the list of |
| 463 // polygons to go into the BSP tree. |
| 464 if (quad.shared_quad_state->sorting_context_id != 0) { |
| 465 scoped_ptr<DrawPolygon> new_polygon(new DrawPolygon( |
| 466 *it, quad.visible_rect, quad.quadTransform(), next_polygon_id++)); |
| 467 if (new_polygon->points().size() > 2u) { |
| 468 poly_list.push_back(new_polygon.Pass()); |
| 469 } |
| 470 continue; |
| 471 } |
| 472 |
| 473 // We are not in a 3d sorting context, so we should draw the quad normally. |
| 474 SetScissorStateForQuad(frame, quad, render_pass_scissor_in_draw_space, |
| 475 render_pass_is_clipped); |
| 476 |
| 477 DoDrawQuad(frame, &quad, nullptr); |
| 478 } |
| 479 FlushPolygons(&poly_list, frame, render_pass_scissor_in_draw_space, |
| 480 render_pass_is_clipped); |
| 481 FinishDrawingQuadList(); |
| 482 } |
| 483 |
| 484 bool DirectRenderer::UseRenderPass(DrawingFrame* frame, |
| 485 const RenderPass* render_pass) { |
| 486 frame->current_render_pass = render_pass; |
| 487 frame->current_texture = NULL; |
| 488 |
| 489 if (render_pass == frame->root_render_pass) { |
| 490 BindFramebufferToOutputSurface(frame); |
| 491 InitializeViewport(frame, |
| 492 render_pass->output_rect, |
| 493 frame->device_viewport_rect, |
| 494 output_surface_->SurfaceSize()); |
| 495 return true; |
| 496 } |
| 497 |
| 498 ScopedResource* texture = render_pass_textures_.get(render_pass->id); |
| 499 DCHECK(texture); |
| 500 |
| 501 gfx::Size size = RenderPassTextureSize(render_pass); |
| 502 size.Enlarge(enlarge_pass_texture_amount_.x(), |
| 503 enlarge_pass_texture_amount_.y()); |
| 504 if (!texture->id()) |
| 505 texture->Allocate( |
| 506 size, ResourceProvider::TEXTURE_HINT_IMMUTABLE_FRAMEBUFFER, RGBA_8888); |
| 507 DCHECK(texture->id()); |
| 508 |
| 509 if (BindFramebufferToTexture(frame, texture, render_pass->output_rect)) { |
| 510 InitializeViewport(frame, render_pass->output_rect, |
| 511 gfx::Rect(render_pass->output_rect.size()), |
| 512 render_pass->output_rect.size()); |
| 513 return true; |
| 514 } |
| 515 |
| 516 return false; |
| 517 } |
| 518 |
| 519 bool DirectRenderer::HasAllocatedResourcesForTesting(RenderPassId id) const { |
| 520 ScopedResource* texture = render_pass_textures_.get(id); |
| 521 return texture && texture->id(); |
| 522 } |
| 523 |
| 524 // static |
| 525 gfx::Size DirectRenderer::RenderPassTextureSize(const RenderPass* render_pass) { |
| 526 return render_pass->output_rect.size(); |
| 527 } |
| 528 |
| 529 } // namespace cc |
OLD | NEW |