| 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/direct_renderer.h" | |
| 6 | |
| 7 #include <vector> | |
| 8 | |
| 9 #include "base/debug/trace_event.h" | |
| 10 #include "base/metrics/histogram.h" | |
| 11 #include "cc/base/math_util.h" | |
| 12 #include "cc/draw_quad.h" | |
| 13 #include "ui/gfx/rect_conversions.h" | |
| 14 #include "ui/gfx/transform.h" | |
| 15 | |
| 16 static gfx::Transform OrthoProjectionMatrix(float left, | |
| 17 float right, | |
| 18 float bottom, | |
| 19 float top) { | |
| 20 // Use the standard formula to map the clipping frustum to the cube from | |
| 21 // [-1, -1, -1] to [1, 1, 1]. | |
| 22 float delta_x = right - left; | |
| 23 float delta_y = top - bottom; | |
| 24 gfx::Transform proj; | |
| 25 if (!delta_x || !delta_y) | |
| 26 return proj; | |
| 27 proj.matrix().setDouble(0, 0, 2.0f / delta_x); | |
| 28 proj.matrix().setDouble(0, 3, -(right + left) / delta_x); | |
| 29 proj.matrix().setDouble(1, 1, 2.0f / delta_y); | |
| 30 proj.matrix().setDouble(1, 3, -(top + bottom) / delta_y); | |
| 31 | |
| 32 // Z component of vertices is always set to zero as we don't use the depth | |
| 33 // buffer while drawing. | |
| 34 proj.matrix().setDouble(2, 2, 0); | |
| 35 | |
| 36 return proj; | |
| 37 } | |
| 38 | |
| 39 static gfx::Transform window_matrix(int x, int y, int width, int height) { | |
| 40 gfx::Transform canvas; | |
| 41 | |
| 42 // Map to window position and scale up to pixel coordinates. | |
| 43 canvas.Translate3d(x, y, 0); | |
| 44 canvas.Scale3d(width, height, 0); | |
| 45 | |
| 46 // Map from ([-1, -1] to [1, 1]) -> ([0, 0] to [1, 1]) | |
| 47 canvas.Translate3d(0.5, 0.5, 0.5); | |
| 48 canvas.Scale3d(0.5, 0.5, 0.5); | |
| 49 | |
| 50 return canvas; | |
| 51 } | |
| 52 | |
| 53 namespace cc { | |
| 54 | |
| 55 DirectRenderer::DrawingFrame::DrawingFrame() | |
| 56 : root_render_pass(NULL), | |
| 57 current_render_pass(NULL), | |
| 58 current_texture(NULL), | |
| 59 flipped_y(false) {} | |
| 60 | |
| 61 DirectRenderer::DrawingFrame::~DrawingFrame() {} | |
| 62 | |
| 63 // | |
| 64 // static | |
| 65 gfx::RectF DirectRenderer::QuadVertexRect() { | |
| 66 return gfx::RectF(-0.5f, -0.5f, 1.f, 1.f); | |
| 67 } | |
| 68 | |
| 69 // static | |
| 70 void DirectRenderer::QuadRectTransform(gfx::Transform* quad_rect_transform, | |
| 71 const gfx::Transform& quadTransform, | |
| 72 const gfx::RectF& quadRect) { | |
| 73 *quad_rect_transform = quadTransform; | |
| 74 quad_rect_transform->Translate(0.5 * quadRect.width() + quadRect.x(), | |
| 75 0.5 * quadRect.height() + quadRect.y()); | |
| 76 quad_rect_transform->Scale(quadRect.width(), quadRect.height()); | |
| 77 } | |
| 78 | |
| 79 // static | |
| 80 void DirectRenderer::InitializeMatrices(DrawingFrame& frame, | |
| 81 gfx::Rect draw_rect, | |
| 82 bool flip_y) { | |
| 83 if (flip_y) { | |
| 84 frame.projection_matrix = OrthoProjectionMatrix(draw_rect.x(), | |
| 85 draw_rect.right(), | |
| 86 draw_rect.bottom(), | |
| 87 draw_rect.y()); | |
| 88 } else { | |
| 89 frame.projection_matrix = OrthoProjectionMatrix(draw_rect.x(), | |
| 90 draw_rect.right(), | |
| 91 draw_rect.y(), | |
| 92 draw_rect.bottom()); | |
| 93 } | |
| 94 frame.window_matrix = | |
| 95 window_matrix(0, 0, draw_rect.width(), draw_rect.height()); | |
| 96 frame.flipped_y = flip_y; | |
| 97 } | |
| 98 | |
| 99 // static | |
| 100 gfx::Rect DirectRenderer::MoveScissorToWindowSpace( | |
| 101 const DrawingFrame& frame, const gfx::RectF& scissor_rect) { | |
| 102 gfx::Rect scissor_rect_in_canvas_space = gfx::ToEnclosingRect(scissor_rect); | |
| 103 // The scissor coordinates must be supplied in viewport space so we need to | |
| 104 // offset by the relative position of the top left corner of the current | |
| 105 // render pass. | |
| 106 gfx::Rect framebuffer_output_rect = frame.current_render_pass->output_rect; | |
| 107 scissor_rect_in_canvas_space.set_x( | |
| 108 scissor_rect_in_canvas_space.x() - framebuffer_output_rect.x()); | |
| 109 if (frame.flipped_y && !frame.current_texture) { | |
| 110 scissor_rect_in_canvas_space.set_y( | |
| 111 framebuffer_output_rect.height() - | |
| 112 (scissor_rect_in_canvas_space.bottom() - framebuffer_output_rect.y())); | |
| 113 } else { | |
| 114 scissor_rect_in_canvas_space.set_y( | |
| 115 scissor_rect_in_canvas_space.y() - framebuffer_output_rect.y()); | |
| 116 } | |
| 117 return scissor_rect_in_canvas_space; | |
| 118 } | |
| 119 | |
| 120 DirectRenderer::DirectRenderer(RendererClient* client, | |
| 121 ResourceProvider* resource_provider) | |
| 122 : Renderer(client), | |
| 123 resource_provider_(resource_provider) {} | |
| 124 | |
| 125 DirectRenderer::~DirectRenderer() {} | |
| 126 | |
| 127 void DirectRenderer::SetEnlargePassTextureAmountForTesting( | |
| 128 gfx::Vector2d amount) { | |
| 129 enlarge_pass_texture_amount_ = amount; | |
| 130 } | |
| 131 | |
| 132 void DirectRenderer::DecideRenderPassAllocationsForFrame( | |
| 133 const RenderPassList& render_passes_in_draw_order) { | |
| 134 base::hash_map<RenderPass::Id, const RenderPass*> renderPassesInFrame; | |
| 135 for (size_t i = 0; i < render_passes_in_draw_order.size(); ++i) | |
| 136 renderPassesInFrame.insert(std::pair<RenderPass::Id, const RenderPass*>( | |
| 137 render_passes_in_draw_order[i]->id, render_passes_in_draw_order[i])); | |
| 138 | |
| 139 std::vector<RenderPass::Id> passes_to_delete; | |
| 140 ScopedPtrHashMap<RenderPass::Id, CachedResource>::const_iterator passIterator; | |
| 141 for (passIterator = render_pass_textures_.begin(); | |
| 142 passIterator != render_pass_textures_.end(); | |
| 143 ++passIterator) { | |
| 144 base::hash_map<RenderPass::Id, const RenderPass*>::const_iterator it = | |
| 145 renderPassesInFrame.find(passIterator->first); | |
| 146 if (it == renderPassesInFrame.end()) { | |
| 147 passes_to_delete.push_back(passIterator->first); | |
| 148 continue; | |
| 149 } | |
| 150 | |
| 151 const RenderPass* render_pass_in_frame = it->second; | |
| 152 gfx::Size required_size = RenderPassTextureSize(render_pass_in_frame); | |
| 153 GLenum required_format = RenderPassTextureFormat(render_pass_in_frame); | |
| 154 CachedResource* texture = passIterator->second; | |
| 155 DCHECK(texture); | |
| 156 | |
| 157 bool size_appropriate = texture->size().width() >= required_size.width() && | |
| 158 texture->size().height() >= required_size.height(); | |
| 159 if (texture->id() && | |
| 160 (!size_appropriate || texture->format() != required_format)) | |
| 161 texture->Free(); | |
| 162 } | |
| 163 | |
| 164 // Delete RenderPass textures from the previous frame that will not be used | |
| 165 // again. | |
| 166 for (size_t i = 0; i < passes_to_delete.size(); ++i) | |
| 167 render_pass_textures_.erase(passes_to_delete[i]); | |
| 168 | |
| 169 for (size_t i = 0; i < render_passes_in_draw_order.size(); ++i) { | |
| 170 if (!render_pass_textures_.contains(render_passes_in_draw_order[i]->id)) { | |
| 171 scoped_ptr<CachedResource> texture = | |
| 172 CachedResource::Create(resource_provider_); | |
| 173 render_pass_textures_.set(render_passes_in_draw_order[i]->id, | |
| 174 texture.Pass()); | |
| 175 } | |
| 176 } | |
| 177 } | |
| 178 | |
| 179 void DirectRenderer::DrawFrame(RenderPassList& render_passes_in_draw_order) { | |
| 180 TRACE_EVENT0("cc", "DirectRenderer::drawFrame"); | |
| 181 UMA_HISTOGRAM_COUNTS("Renderer4.renderPassCount", | |
| 182 render_passes_in_draw_order.size()); | |
| 183 | |
| 184 const RenderPass* root_render_pass = render_passes_in_draw_order.back(); | |
| 185 DCHECK(root_render_pass); | |
| 186 | |
| 187 DrawingFrame frame; | |
| 188 frame.root_render_pass = root_render_pass; | |
| 189 frame.root_damage_rect = | |
| 190 Capabilities().using_partial_swap ? | |
| 191 root_render_pass->damage_rect : root_render_pass->output_rect; | |
| 192 frame.root_damage_rect.Intersect(gfx::Rect(gfx::Point(), ViewportSize())); | |
| 193 | |
| 194 BeginDrawingFrame(frame); | |
| 195 for (size_t i = 0; i < render_passes_in_draw_order.size(); ++i) | |
| 196 DrawRenderPass(frame, render_passes_in_draw_order[i]); | |
| 197 FinishDrawingFrame(frame); | |
| 198 | |
| 199 render_passes_in_draw_order.clear(); | |
| 200 } | |
| 201 | |
| 202 gfx::RectF DirectRenderer::ComputeScissorRectForRenderPass( | |
| 203 const DrawingFrame& frame) { | |
| 204 gfx::RectF render_pass_scissor = frame.current_render_pass->output_rect; | |
| 205 | |
| 206 if (frame.root_damage_rect == frame.root_render_pass->output_rect) | |
| 207 return render_pass_scissor; | |
| 208 | |
| 209 gfx::Transform inverseTransform(gfx::Transform::kSkipInitialization); | |
| 210 if (frame.current_render_pass->transform_to_root_target.GetInverse( | |
| 211 &inverseTransform)) { | |
| 212 // Only intersect inverse-projected damage if the transform is invertible. | |
| 213 gfx::RectF damage_rect_in_render_pass_space = | |
| 214 MathUtil::ProjectClippedRect(inverseTransform, frame.root_damage_rect); | |
| 215 render_pass_scissor.Intersect(damage_rect_in_render_pass_space); | |
| 216 } | |
| 217 | |
| 218 return render_pass_scissor; | |
| 219 } | |
| 220 | |
| 221 void DirectRenderer::SetScissorStateForQuad(const DrawingFrame& frame, | |
| 222 const DrawQuad& quad) { | |
| 223 if (quad.isClipped()) { | |
| 224 gfx::RectF quad_scissor_rect = quad.clipRect(); | |
| 225 SetScissorTestRect(MoveScissorToWindowSpace(frame, quad_scissor_rect)); | |
| 226 } else { | |
| 227 EnsureScissorTestDisabled(); | |
| 228 } | |
| 229 } | |
| 230 | |
| 231 void DirectRenderer::SetScissorStateForQuadWithRenderPassScissor( | |
| 232 const DrawingFrame& frame, | |
| 233 const DrawQuad& quad, | |
| 234 const gfx::RectF& render_pass_scissor, | |
| 235 bool* should_skip_quad) { | |
| 236 gfx::RectF quad_scissor_rect = render_pass_scissor; | |
| 237 | |
| 238 if (quad.isClipped()) | |
| 239 quad_scissor_rect.Intersect(quad.clipRect()); | |
| 240 | |
| 241 if (quad_scissor_rect.IsEmpty()) { | |
| 242 *should_skip_quad = true; | |
| 243 return; | |
| 244 } | |
| 245 | |
| 246 *should_skip_quad = false; | |
| 247 SetScissorTestRect(MoveScissorToWindowSpace(frame, quad_scissor_rect)); | |
| 248 } | |
| 249 | |
| 250 void DirectRenderer::FinishDrawingQuadList() {} | |
| 251 | |
| 252 void DirectRenderer::DrawRenderPass(DrawingFrame& frame, | |
| 253 const RenderPass* render_pass) { | |
| 254 TRACE_EVENT0("cc", "DirectRenderer::drawRenderPass"); | |
| 255 if (!UseRenderPass(frame, render_pass)) | |
| 256 return; | |
| 257 | |
| 258 bool using_scissor_as_optimization = Capabilities().using_partial_swap; | |
| 259 gfx::RectF render_pass_scissor; | |
| 260 | |
| 261 if (using_scissor_as_optimization) { | |
| 262 render_pass_scissor = ComputeScissorRectForRenderPass(frame); | |
| 263 SetScissorTestRect(MoveScissorToWindowSpace(frame, render_pass_scissor)); | |
| 264 } | |
| 265 | |
| 266 if (frame.current_render_pass != frame.root_render_pass || | |
| 267 client_->ShouldClearRootRenderPass()) { | |
| 268 if (!using_scissor_as_optimization) | |
| 269 EnsureScissorTestDisabled(); | |
| 270 ClearFramebuffer(frame); | |
| 271 } | |
| 272 | |
| 273 const QuadList& quad_list = render_pass->quad_list; | |
| 274 for (QuadList::constBackToFrontIterator it = quad_list.backToFrontBegin(); | |
| 275 it != quad_list.backToFrontEnd(); | |
| 276 ++it) { | |
| 277 const DrawQuad& quad = *(*it); | |
| 278 bool should_skip_quad = false; | |
| 279 | |
| 280 if (using_scissor_as_optimization) { | |
| 281 SetScissorStateForQuadWithRenderPassScissor( | |
| 282 frame, quad, render_pass_scissor, &should_skip_quad); | |
| 283 } else { | |
| 284 SetScissorStateForQuad(frame, quad); | |
| 285 } | |
| 286 | |
| 287 if (!should_skip_quad) | |
| 288 DoDrawQuad(frame, *it); | |
| 289 } | |
| 290 FinishDrawingQuadList(); | |
| 291 | |
| 292 CachedResource* texture = render_pass_textures_.get(render_pass->id); | |
| 293 if (texture) { | |
| 294 texture->set_is_complete( | |
| 295 !render_pass->has_occlusion_from_outside_target_surface); | |
| 296 } | |
| 297 } | |
| 298 | |
| 299 bool DirectRenderer::UseRenderPass(DrawingFrame& frame, | |
| 300 const RenderPass* render_pass) { | |
| 301 frame.current_render_pass = render_pass; | |
| 302 frame.current_texture = NULL; | |
| 303 | |
| 304 if (render_pass == frame.root_render_pass) { | |
| 305 BindFramebufferToOutputSurface(frame); | |
| 306 InitializeMatrices(frame, render_pass->output_rect, FlippedFramebuffer()); | |
| 307 SetDrawViewportSize(render_pass->output_rect.size()); | |
| 308 return true; | |
| 309 } | |
| 310 | |
| 311 CachedResource* texture = render_pass_textures_.get(render_pass->id); | |
| 312 DCHECK(texture); | |
| 313 | |
| 314 gfx::Size size = RenderPassTextureSize(render_pass); | |
| 315 size.Enlarge(enlarge_pass_texture_amount_.x(), | |
| 316 enlarge_pass_texture_amount_.y()); | |
| 317 if (!texture->id() && | |
| 318 !texture->Allocate(size, | |
| 319 RenderPassTextureFormat(render_pass), | |
| 320 ResourceProvider::TextureUsageFramebuffer)) | |
| 321 return false; | |
| 322 | |
| 323 return BindFramebufferToTexture(frame, texture, render_pass->output_rect); | |
| 324 } | |
| 325 | |
| 326 bool DirectRenderer::HaveCachedResourcesForRenderPassId(RenderPass::Id id) | |
| 327 const { | |
| 328 if (!Settings().cacheRenderPassContents) | |
| 329 return false; | |
| 330 | |
| 331 CachedResource* texture = render_pass_textures_.get(id); | |
| 332 return texture && texture->id() && texture->is_complete(); | |
| 333 } | |
| 334 | |
| 335 // static | |
| 336 gfx::Size DirectRenderer::RenderPassTextureSize(const RenderPass* render_pass) { | |
| 337 return render_pass->output_rect.size(); | |
| 338 } | |
| 339 | |
| 340 // static | |
| 341 GLenum DirectRenderer::RenderPassTextureFormat(const RenderPass* render_pass) { | |
| 342 return GL_RGBA; | |
| 343 } | |
| 344 | |
| 345 } // namespace cc | |
| OLD | NEW |