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 |