WebKit Roll 139512:139548
[chromium-blink-merge.git] / cc / direct_renderer.cc
blob027b09a395cda50fe2f13d62edd5564bd00a5cbe
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.
5 #include "cc/direct_renderer.h"
7 #include <vector>
9 #include "base/debug/trace_event.h"
10 #include "base/metrics/histogram.h"
11 #include "cc/math_util.h"
12 #include "ui/gfx/rect_conversions.h"
13 #include "ui/gfx/transform.h"
15 static gfx::Transform orthoProjectionMatrix(float left, float right, float bottom, float top)
17 // Use the standard formula to map the clipping frustum to the cube from
18 // [-1, -1, -1] to [1, 1, 1].
19 float deltaX = right - left;
20 float deltaY = top - bottom;
21 gfx::Transform proj;
22 if (!deltaX || !deltaY)
23 return proj;
24 proj.matrix().setDouble(0, 0, 2.0f / deltaX);
25 proj.matrix().setDouble(0, 3, -(right + left) / deltaX);
26 proj.matrix().setDouble(1, 1, 2.0f / deltaY);
27 proj.matrix().setDouble(1, 3, -(top + bottom) / deltaY);
29 // Z component of vertices is always set to zero as we don't use the depth buffer
30 // while drawing.
31 proj.matrix().setDouble(2, 2, 0);
33 return proj;
36 static gfx::Transform windowMatrix(int x, int y, int width, int height)
38 gfx::Transform canvas;
40 // Map to window position and scale up to pixel coordinates.
41 canvas.Translate3d(x, y, 0);
42 canvas.Scale3d(width, height, 0);
44 // Map from ([-1, -1] to [1, 1]) -> ([0, 0] to [1, 1])
45 canvas.Translate3d(0.5, 0.5, 0.5);
46 canvas.Scale3d(0.5, 0.5, 0.5);
48 return canvas;
51 namespace cc {
53 DirectRenderer::DrawingFrame::DrawingFrame()
54 : rootRenderPass(0)
55 , currentRenderPass(0)
56 , currentTexture(0)
57 , flippedY(false)
61 DirectRenderer::DrawingFrame::~DrawingFrame()
66 // static
67 gfx::RectF DirectRenderer::quadVertexRect()
69 return gfx::RectF(-0.5, -0.5, 1, 1);
72 // static
73 void DirectRenderer::quadRectTransform(gfx::Transform* quadRectTransform, const gfx::Transform& quadTransform, const gfx::RectF& quadRect)
75 *quadRectTransform = quadTransform;
76 quadRectTransform->Translate(0.5 * quadRect.width() + quadRect.x(), 0.5 * quadRect.height() + quadRect.y());
77 quadRectTransform->Scale(quadRect.width(), quadRect.height());
80 // static
81 void DirectRenderer::initializeMatrices(DrawingFrame& frame, const gfx::Rect& drawRect, bool flipY)
83 if (flipY)
84 frame.projectionMatrix = orthoProjectionMatrix(drawRect.x(), drawRect.right(), drawRect.bottom(), drawRect.y());
85 else
86 frame.projectionMatrix = orthoProjectionMatrix(drawRect.x(), drawRect.right(), drawRect.y(), drawRect.bottom());
87 frame.windowMatrix = windowMatrix(0, 0, drawRect.width(), drawRect.height());
88 frame.flippedY = flipY;
91 // static
92 gfx::Rect DirectRenderer::moveScissorToWindowSpace(const DrawingFrame& frame, gfx::RectF scissorRect)
94 gfx::Rect scissorRectInCanvasSpace = gfx::ToEnclosingRect(scissorRect);
95 // The scissor coordinates must be supplied in viewport space so we need to offset
96 // by the relative position of the top left corner of the current render pass.
97 gfx::Rect framebufferOutputRect = frame.currentRenderPass->output_rect;
98 scissorRectInCanvasSpace.set_x(scissorRectInCanvasSpace.x() - framebufferOutputRect.x());
99 if (frame.flippedY && !frame.currentTexture)
100 scissorRectInCanvasSpace.set_y(framebufferOutputRect.height() - (scissorRectInCanvasSpace.bottom() - framebufferOutputRect.y()));
101 else
102 scissorRectInCanvasSpace.set_y(scissorRectInCanvasSpace.y() - framebufferOutputRect.y());
103 return scissorRectInCanvasSpace;
106 DirectRenderer::DirectRenderer(RendererClient* client, ResourceProvider* resourceProvider)
107 : Renderer(client)
108 , m_resourceProvider(resourceProvider)
112 DirectRenderer::~DirectRenderer()
116 void DirectRenderer::setEnlargePassTextureAmountForTesting(gfx::Vector2d amount)
118 m_enlargePassTextureAmount = amount;
121 void DirectRenderer::decideRenderPassAllocationsForFrame(const RenderPassList& renderPassesInDrawOrder)
123 base::hash_map<RenderPass::Id, const RenderPass*> renderPassesInFrame;
124 for (size_t i = 0; i < renderPassesInDrawOrder.size(); ++i)
125 renderPassesInFrame.insert(std::pair<RenderPass::Id, const RenderPass*>(renderPassesInDrawOrder[i]->id, renderPassesInDrawOrder[i]));
127 std::vector<RenderPass::Id> passesToDelete;
128 ScopedPtrHashMap<RenderPass::Id, CachedResource>::const_iterator passIterator;
129 for (passIterator = m_renderPassTextures.begin(); passIterator != m_renderPassTextures.end(); ++passIterator) {
130 base::hash_map<RenderPass::Id, const RenderPass*>::const_iterator it = renderPassesInFrame.find(passIterator->first);
131 if (it == renderPassesInFrame.end()) {
132 passesToDelete.push_back(passIterator->first);
133 continue;
136 const RenderPass* renderPassInFrame = it->second;
137 const gfx::Size& requiredSize = renderPassTextureSize(renderPassInFrame);
138 GLenum requiredFormat = renderPassTextureFormat(renderPassInFrame);
139 CachedResource* texture = passIterator->second;
140 DCHECK(texture);
142 bool sizeAppropriate = texture->size().width() >= requiredSize.width() &&
143 texture->size().height() >= requiredSize.height();
144 if (texture->id() && (!sizeAppropriate || texture->format() != requiredFormat))
145 texture->Free();
148 // Delete RenderPass textures from the previous frame that will not be used again.
149 for (size_t i = 0; i < passesToDelete.size(); ++i)
150 m_renderPassTextures.erase(passesToDelete[i]);
152 for (size_t i = 0; i < renderPassesInDrawOrder.size(); ++i) {
153 if (!m_renderPassTextures.contains(renderPassesInDrawOrder[i]->id)) {
154 scoped_ptr<CachedResource> texture = CachedResource::create(m_resourceProvider);
155 m_renderPassTextures.set(renderPassesInDrawOrder[i]->id, texture.Pass());
160 void DirectRenderer::drawFrame(RenderPassList& renderPassesInDrawOrder)
162 TRACE_EVENT0("cc", "DirectRenderer::drawFrame");
163 HISTOGRAM_COUNTS("Renderer4.renderPassCount", renderPassesInDrawOrder.size());
165 const RenderPass* rootRenderPass = renderPassesInDrawOrder.back();
166 DCHECK(rootRenderPass);
168 DrawingFrame frame;
169 frame.rootRenderPass = rootRenderPass;
170 frame.rootDamageRect = capabilities().usingPartialSwap ? rootRenderPass->damage_rect : rootRenderPass->output_rect;
171 frame.rootDamageRect.Intersect(gfx::Rect(gfx::Point(), viewportSize()));
173 beginDrawingFrame(frame);
174 for (size_t i = 0; i < renderPassesInDrawOrder.size(); ++i)
175 drawRenderPass(frame, renderPassesInDrawOrder[i]);
176 finishDrawingFrame(frame);
178 renderPassesInDrawOrder.clear();
181 gfx::RectF DirectRenderer::computeScissorRectForRenderPass(const DrawingFrame& frame)
183 gfx::RectF renderPassScissor = frame.currentRenderPass->output_rect;
185 if (frame.rootDamageRect == frame.rootRenderPass->output_rect)
186 return renderPassScissor;
188 gfx::Transform inverseTransform(gfx::Transform::kSkipInitialization);
189 if (frame.currentRenderPass->transform_to_root_target.GetInverse(&inverseTransform)) {
190 // Only intersect inverse-projected damage if the transform is invertible.
191 gfx::RectF damageRectInRenderPassSpace = MathUtil::projectClippedRect(inverseTransform, frame.rootDamageRect);
192 renderPassScissor.Intersect(damageRectInRenderPassSpace);
195 return renderPassScissor;
198 void DirectRenderer::setScissorStateForQuad(const DrawingFrame& frame, const DrawQuad& quad)
200 if (quad.isClipped()) {
201 gfx::RectF quadScissorRect = quad.clipRect();
202 setScissorTestRect(moveScissorToWindowSpace(frame, quadScissorRect));
204 else
205 ensureScissorTestDisabled();
208 void DirectRenderer::setScissorStateForQuadWithRenderPassScissor(const DrawingFrame& frame, const DrawQuad& quad, const gfx::RectF& renderPassScissor, bool* shouldSkipQuad)
210 gfx::RectF quadScissorRect = renderPassScissor;
212 if (quad.isClipped())
213 quadScissorRect.Intersect(quad.clipRect());
215 if (quadScissorRect.IsEmpty()) {
216 *shouldSkipQuad = true;
217 return;
220 *shouldSkipQuad = false;
221 setScissorTestRect(moveScissorToWindowSpace(frame, quadScissorRect));
224 void DirectRenderer::finishDrawingQuadList()
228 void DirectRenderer::drawRenderPass(DrawingFrame& frame, const RenderPass* renderPass)
230 TRACE_EVENT0("cc", "DirectRenderer::drawRenderPass");
231 if (!useRenderPass(frame, renderPass))
232 return;
234 bool usingScissorAsOptimization = capabilities().usingPartialSwap;
235 gfx::RectF renderPassScissor;
237 if (usingScissorAsOptimization) {
238 renderPassScissor = computeScissorRectForRenderPass(frame);
239 setScissorTestRect(moveScissorToWindowSpace(frame, renderPassScissor));
242 if (frame.currentRenderPass != frame.rootRenderPass || m_client->shouldClearRootRenderPass())
243 clearFramebuffer(frame);
245 const QuadList& quadList = renderPass->quad_list;
246 for (QuadList::constBackToFrontIterator it = quadList.backToFrontBegin(); it != quadList.backToFrontEnd(); ++it) {
247 const DrawQuad& quad = *(*it);
248 bool shouldSkipQuad = false;
250 if (usingScissorAsOptimization)
251 setScissorStateForQuadWithRenderPassScissor(frame, quad, renderPassScissor, &shouldSkipQuad);
252 else
253 setScissorStateForQuad(frame, quad);
255 if (!shouldSkipQuad)
256 drawQuad(frame, *it);
258 finishDrawingQuadList();
260 CachedResource* texture = m_renderPassTextures.get(renderPass->id);
261 if (texture)
262 texture->setIsComplete(!renderPass->has_occlusion_from_outside_target_surface);
265 bool DirectRenderer::useRenderPass(DrawingFrame& frame, const RenderPass* renderPass)
267 frame.currentRenderPass = renderPass;
268 frame.currentTexture = 0;
270 if (renderPass == frame.rootRenderPass) {
271 bindFramebufferToOutputSurface(frame);
272 initializeMatrices(frame, renderPass->output_rect, flippedFramebuffer());
273 setDrawViewportSize(renderPass->output_rect.size());
274 return true;
277 CachedResource* texture = m_renderPassTextures.get(renderPass->id);
278 DCHECK(texture);
280 gfx::Size size = renderPassTextureSize(renderPass);
281 size.Enlarge(m_enlargePassTextureAmount.x(), m_enlargePassTextureAmount.y());
282 if (!texture->id() && !texture->Allocate(size, renderPassTextureFormat(renderPass), ResourceProvider::TextureUsageFramebuffer))
283 return false;
285 return bindFramebufferToTexture(frame, texture, renderPass->output_rect);
288 bool DirectRenderer::haveCachedResourcesForRenderPassId(RenderPass::Id id) const
290 CachedResource* texture = m_renderPassTextures.get(id);
291 return texture && texture->id() && texture->isComplete();
294 // static
295 gfx::Size DirectRenderer::renderPassTextureSize(const RenderPass* pass)
297 return pass->output_rect.size();
300 // static
301 GLenum DirectRenderer::renderPassTextureFormat(const RenderPass*)
303 return GL_RGBA;
306 } // namespace cc