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"
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
;
22 if (!deltaX
|| !deltaY
)
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
31 proj
.matrix().setDouble(2, 2, 0);
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);
53 DirectRenderer::DrawingFrame::DrawingFrame()
55 , currentRenderPass(0)
61 DirectRenderer::DrawingFrame::~DrawingFrame()
67 gfx::RectF
DirectRenderer::quadVertexRect()
69 return gfx::RectF(-0.5, -0.5, 1, 1);
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());
81 void DirectRenderer::initializeMatrices(DrawingFrame
& frame
, const gfx::Rect
& drawRect
, bool flipY
)
84 frame
.projectionMatrix
= orthoProjectionMatrix(drawRect
.x(), drawRect
.right(), drawRect
.bottom(), drawRect
.y());
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
;
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()));
102 scissorRectInCanvasSpace
.set_y(scissorRectInCanvasSpace
.y() - framebufferOutputRect
.y());
103 return scissorRectInCanvasSpace
;
106 DirectRenderer::DirectRenderer(RendererClient
* client
, ResourceProvider
* resourceProvider
)
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
);
136 const RenderPass
* renderPassInFrame
= it
->second
;
137 const gfx::Size
& requiredSize
= renderPassTextureSize(renderPassInFrame
);
138 GLenum requiredFormat
= renderPassTextureFormat(renderPassInFrame
);
139 CachedResource
* texture
= passIterator
->second
;
142 bool sizeAppropriate
= texture
->size().width() >= requiredSize
.width() &&
143 texture
->size().height() >= requiredSize
.height();
144 if (texture
->id() && (!sizeAppropriate
|| texture
->format() != requiredFormat
))
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
);
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
));
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;
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
))
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
);
253 setScissorStateForQuad(frame
, quad
);
256 drawQuad(frame
, *it
);
258 finishDrawingQuadList();
260 CachedResource
* texture
= m_renderPassTextures
.get(renderPass
->id
);
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());
277 CachedResource
* texture
= m_renderPassTextures
.get(renderPass
->id
);
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
))
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();
295 gfx::Size
DirectRenderer::renderPassTextureSize(const RenderPass
* pass
)
297 return pass
->output_rect
.size();
301 GLenum
DirectRenderer::renderPassTextureFormat(const RenderPass
*)