OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2011 The Chromium OS 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 "window_manager/compositor/xrender/xrender_visitor.h" | |
6 | |
7 #include <X11/extensions/Xrender.h> | |
8 | |
9 #include "base/basictypes.h" | |
10 #include "base/logging.h" | |
11 #include "base/scoped_ptr.h" | |
12 #include "window_manager/image_container.h" | |
13 #include "window_manager/image_enums.h" | |
14 #include "window_manager/util.h" | |
15 #include "window_manager/x11/x_connection.h" | |
16 | |
17 | |
18 #ifndef COMPOSITOR_XRENDER | |
19 #error Need COMPOSITOR_XRENDER defined to compile this file | |
20 #endif | |
21 | |
22 namespace window_manager { | |
23 | |
24 const int kRGBPictureBitDepth = 24; | |
25 const int kRGBAPictureBitDepth = 32; | |
26 | |
27 class XRenderPictureData : public TextureData { | |
28 public: | |
29 XRenderPictureData(XConnection* xconn) | |
30 : pixmap_(0), | |
31 xconn_(xconn) { | |
32 } | |
33 virtual ~XRenderPictureData() { | |
34 xconn_->RenderFreePicture(texture()); | |
35 } | |
36 | |
37 // Initialize our texture and make it contain the current contents of the | |
38 // passed-in pixmap. False is returned if the process fails (in | |
39 // which case this object should be thrown away). | |
40 bool Init(XPixmap pixmap, int bpp) { | |
41 XPicture picture = xconn_->RenderCreatePicture(pixmap, bpp); | |
42 set_texture(picture); | |
43 return (picture != None); | |
44 } | |
45 | |
46 private: | |
47 // The actor's X pixmap. Ownership of the pixmap remains with the caller. | |
48 XPixmap pixmap_; | |
49 | |
50 XConnection* xconn_; // Not owned. | |
51 }; | |
52 | |
53 bool XRenderDrawVisitor::FreeXResources() { | |
Daniel Erat
2011/04/05 01:35:06
move this and AllocateXResources() down. the meth
marcheu
2011/04/05 02:07:42
Done.
| |
54 return xconn_->FreePixmap(back_pixmap_) && | |
55 xconn_->RenderFreePicture(back_picture_) && | |
Daniel Erat
2011/04/05 01:35:06
fix indenting: line this up with the xconn_ on the
marcheu
2011/04/05 02:07:42
Done.
| |
56 xconn_->RenderFreePicture(stage_picture_); | |
57 } | |
58 | |
59 bool XRenderDrawVisitor::AllocateXResources(Compositor::StageActor* stage) { | |
60 // Find root window geometry. | |
61 root_window_ = stage->GetStageXWindow(); | |
62 xconn_->GetWindowGeometry(root_window_, &root_geometry_); | |
63 | |
64 // Create back pixmap. | |
65 back_pixmap_ = | |
66 xconn_->CreatePixmap( | |
67 root_window_, | |
68 root_geometry_.bounds.size(), | |
69 root_geometry_.depth); | |
70 | |
71 // Create back picture. | |
72 back_picture_ = xconn_->RenderCreatePicture(back_pixmap_, | |
73 kRGBPictureBitDepth); | |
74 | |
75 // Create stage picture. | |
76 stage_picture_ = xconn_->RenderCreatePicture(root_window_, | |
77 kRGBPictureBitDepth); | |
78 | |
79 return (back_pixmap_ != None) && | |
80 (back_picture_ != None) && | |
81 (stage_picture_ != None); | |
82 } | |
83 | |
84 | |
85 XRenderDrawVisitor::XRenderDrawVisitor(RealCompositor* compositor, | |
86 Compositor::StageActor* stage) | |
87 : root_window_(None), | |
88 root_geometry_(), | |
Daniel Erat
2011/04/05 01:35:06
nit: no need to list objects with reasonable defau
marcheu
2011/04/05 02:07:42
Done.
| |
89 back_picture_(None), | |
90 back_pixmap_(None), | |
91 stage_picture_(None), | |
92 compositor_(NULL), | |
93 xconn_(compositor->x_conn()), | |
94 stage_(NULL), | |
95 ancestor_opacity_(1.0), | |
96 has_fullscreen_actor_(false) { | |
97 // Check for the XRender extension. | |
98 CHECK(xconn_->RenderQueryExtension()); | |
99 | |
100 CHECK(AllocateXResources(stage)); | |
101 } | |
102 | |
103 XRenderDrawVisitor::~XRenderDrawVisitor() { | |
Daniel Erat
2011/04/05 01:35:06
call FreeXResources() here
marcheu
2011/04/05 02:07:42
Done.
| |
104 } | |
105 | |
106 void XRenderDrawVisitor::BindImage(const ImageContainer* container, | |
107 RealCompositor::ImageActor* actor) { | |
108 XPixmap pixmap = xconn_->CreatePixmapFromContainer(*container); | |
109 | |
110 scoped_ptr<window_manager::XRenderPictureData> | |
111 data(new XRenderPictureData(this->xconn_)); | |
112 data->Init(pixmap, kRGBAPictureBitDepth); | |
113 actor->set_texture_data(data.release()); | |
114 } | |
115 | |
116 void XRenderDrawVisitor::VisitImage(RealCompositor::ImageActor* actor) { | |
117 if (!actor->IsVisible()) | |
118 return; | |
119 | |
120 // All ImageActors are also QuadActors, and so we let the | |
121 // QuadActor do all the actual drawing. | |
122 VisitQuad(actor); | |
123 } | |
124 | |
125 void XRenderDrawVisitor::VisitTexturePixmap( | |
126 RealCompositor::TexturePixmapActor* actor) { | |
127 if (!actor->IsVisible()) | |
128 return; | |
129 | |
130 // Make sure we have an XRender pic for this pixmap | |
131 if (!actor->texture_data()) { | |
132 if (actor->pixmap()) { | |
133 scoped_ptr<window_manager::XRenderPictureData> | |
134 data(new XRenderPictureData(this->xconn_)); | |
135 data->Init(actor->pixmap(), | |
136 actor->pixmap_is_opaque() ? | |
137 kRGBPictureBitDepth : kRGBAPictureBitDepth); | |
138 actor->set_texture_data(data.release()); | |
139 } | |
140 } | |
141 | |
142 // All texture pixmaps are also QuadActors, and so we let the | |
143 // QuadActor do all the actual drawing. | |
144 VisitQuad(actor); | |
145 } | |
146 | |
147 void XRenderDrawVisitor::VisitQuad(RealCompositor::QuadActor* actor) { | |
148 if (!actor->IsVisible()) | |
149 return; | |
150 | |
151 #ifdef EXTRA_LOGGING | |
152 DLOG(INFO) << "Drawing quad " << actor->name() << "."; | |
153 #endif | |
154 | |
155 // Calculate the vertex colors, taking into account the actor color, | |
156 // opacity and the dimming gradient. | |
157 float actor_opacity = actor->is_opaque() ? | |
158 1.f : | |
159 actor->opacity() * ancestor_opacity_; | |
160 float dimmed_transparency_begin = 1.f - actor->dimmed_opacity_begin(); | |
161 float dimmed_transparency_end = 1.f - actor->dimmed_opacity_end(); | |
162 float red = actor->color().red; | |
163 float green = actor->color().green; | |
164 float blue = actor->color().blue; | |
165 DCHECK_LE(actor_opacity, 1.f); | |
166 DCHECK_GE(actor_opacity, 0.f); | |
167 DCHECK_LE(dimmed_transparency_begin, 1.f); | |
168 DCHECK_GE(dimmed_transparency_begin, 0.f); | |
169 DCHECK_LE(dimmed_transparency_end, 1.f); | |
170 DCHECK_GE(dimmed_transparency_end, 0.f); | |
171 DCHECK_LE(red, 1.f); | |
172 DCHECK_GE(red, 0.f); | |
173 DCHECK_LE(green, 1.f); | |
174 DCHECK_GE(green, 0.f); | |
175 DCHECK_LE(blue, 1.f); | |
176 DCHECK_GE(blue, 0.f); | |
177 | |
178 xconn_->RenderComposite( | |
179 !actor->is_opaque(), | |
180 static_cast<XPicture>(actor->texture_data()->texture()), | |
181 static_cast<XPicture>(None), | |
182 back_picture_, | |
183 Point(0, 0), | |
184 Point(0, 0), | |
185 actor->model_view(), | |
186 actor->GetBounds().size()); | |
187 } | |
188 | |
189 void XRenderDrawVisitor::VisitStage(RealCompositor::StageActor* actor) { | |
190 if (!actor->IsVisible()) | |
191 return; | |
192 | |
193 stage_ = actor; | |
194 | |
195 if (actor->was_resized()) { | |
196 CHECK(FreeXResources()); | |
197 CHECK(AllocateXResources(actor)); | |
198 actor->unset_was_resized(); | |
199 } | |
200 | |
201 // If we don't have a full screen actor we do a fill with the stage color. | |
202 if (!has_fullscreen_actor_) { | |
203 const Compositor::Color& color = actor->stage_color(); | |
204 xconn_->RenderFillRectangle(back_picture_, | |
205 color.red, | |
206 color.green, | |
207 color.blue, | |
208 Point(0, 0), | |
209 root_geometry_.bounds.size()); | |
210 } | |
211 | |
212 #ifdef EXTRA_LOGGING | |
213 DLOG(INFO) << "Starting Render pass."; | |
214 #endif | |
215 | |
216 ancestor_opacity_ = actor->opacity(); | |
217 | |
218 // Walk the actors and render them | |
219 VisitContainer(actor); | |
220 | |
221 #ifdef EXTRA_LOGGING | |
222 DLOG(INFO) << "Ending Render pass."; | |
223 #endif | |
224 | |
225 if (!damaged_region_.empty()) { | |
226 Matrix4 identity = Matrix4::identity(); | |
227 identity[0][0] = damaged_region_.width; | |
228 identity[1][1] = damaged_region_.height; | |
229 identity[3][0] = damaged_region_.x; | |
230 identity[3][1] = root_geometry_.bounds.height - | |
231 damaged_region_.y - damaged_region_.height; | |
232 | |
233 xconn_->RenderComposite(false, | |
234 back_picture_, | |
235 None, | |
236 stage_picture_, | |
237 Point(damaged_region_.x, | |
238 root_geometry_.bounds.height - | |
239 damaged_region_.y - | |
240 damaged_region_.height), | |
241 Point(0, 0), | |
242 identity, | |
243 damaged_region_.size()); | |
244 } else { | |
245 Matrix4 identity = Vectormath::Aos::Matrix4::identity(); | |
246 identity[0][0] = root_geometry_.bounds.width; | |
247 identity[1][1] = root_geometry_.bounds.height; | |
248 xconn_->RenderComposite(false, | |
249 back_picture_, | |
250 None, | |
251 stage_picture_, | |
252 Point(0, 0), | |
253 Point(0, 0), | |
254 identity, | |
255 root_geometry_.bounds.size()); | |
256 } | |
257 | |
258 stage_ = NULL; | |
259 } | |
260 | |
261 void XRenderDrawVisitor::VisitContainer(RealCompositor::ContainerActor* actor) { | |
262 if (!actor->IsVisible()) | |
263 return; | |
264 | |
265 #ifdef EXTRA_LOGGING | |
266 DLOG(INFO) << "Drawing container " << actor->name() << "."; | |
267 DLOG(INFO) << " at: (" << actor->x() << ", " << actor->y() | |
268 << ", " << actor->z() << ") with scale: (" | |
269 << actor->scale_x() << ", " << actor->scale_y() << ") at size (" | |
270 << actor->width() << "x" << actor->height() << ")"; | |
271 #endif | |
272 RealCompositor::ActorVector children = actor->GetChildren(); | |
273 | |
274 float original_opacity = ancestor_opacity_; | |
275 ancestor_opacity_ *= actor->opacity(); | |
276 | |
277 // Walk backwards so we go back to front. | |
278 RealCompositor::ActorVector::const_reverse_iterator iterator; | |
279 for (iterator = children.rbegin(); iterator != children.rend(); | |
280 ++iterator) { | |
281 RealCompositor::Actor* child = *iterator; | |
282 | |
283 if (child->IsVisible()) { | |
284 #ifdef EXTRA_LOGGING | |
285 DLOG(INFO) << "Drawing child " << child->name() | |
286 << " (visible: " << child->IsVisible() | |
287 << ", has_children: " << child->has_children() | |
288 << ", opacity: " << child->opacity() | |
289 << ", ancestor_opacity: " << ancestor_opacity_ | |
290 << ", is_opaque: " << child->is_opaque() << ")"; | |
291 #endif | |
292 child->Accept(this); | |
293 } else { | |
294 #ifdef EXTRA_LOGGING | |
295 DLOG(INFO) << "NOT drawing child " << child->name() | |
296 << " (visible: " << child->IsVisible() | |
297 << ", has_children: " << child->has_children() | |
298 << ", opacity: " << child->opacity() | |
299 << ", ancestor_opacity: " << ancestor_opacity_ | |
300 << ", is_opaque: " << child->is_opaque() << ")"; | |
301 #endif | |
302 } | |
303 | |
304 // Reset ancestor opacity. | |
305 ancestor_opacity_ = original_opacity; | |
306 } | |
307 } | |
308 | |
309 } // namespace window_manager | |
OLD | NEW |