OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "cc/resources/video_resource_updater.h" | 5 #include "cc/resources/video_resource_updater.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "cc/output/gl_renderer.h" | 8 #include "cc/output/gl_renderer.h" |
9 #include "cc/resources/resource_provider.h" | 9 #include "cc/resources/resource_provider.h" |
10 #include "gpu/GLES2/gl2extchromium.h" | 10 #include "gpu/GLES2/gl2extchromium.h" |
11 #include "media/base/video_frame.h" | 11 #include "media/base/video_frame.h" |
12 #include "media/filters/skcanvas_video_renderer.h" | 12 #include "media/filters/skcanvas_video_renderer.h" |
13 #include "third_party/khronos/GLES2/gl2.h" | 13 #include "third_party/khronos/GLES2/gl2.h" |
14 #include "third_party/khronos/GLES2/gl2ext.h" | 14 #include "third_party/khronos/GLES2/gl2ext.h" |
15 #include "ui/gfx/size_conversions.h" | 15 #include "ui/gfx/size_conversions.h" |
16 | 16 |
17 const unsigned kYUVResourceFormat = GL_LUMINANCE; | 17 const unsigned kYUVResourceFormat = GL_LUMINANCE; |
18 const unsigned kRGBResourceFormat = GL_RGBA; | 18 const unsigned kRGBResourceFormat = GL_RGBA; |
19 | 19 |
20 namespace cc { | 20 namespace cc { |
21 | 21 |
22 VideoFrameExternalResources::VideoFrameExternalResources() : type(NONE) {} | 22 VideoFrameExternalResources::VideoFrameExternalResources() : type(NONE) {} |
23 | 23 |
24 VideoFrameExternalResources::~VideoFrameExternalResources() {} | 24 VideoFrameExternalResources::~VideoFrameExternalResources() {} |
25 | 25 |
26 VideoResourceUpdater::VideoResourceUpdater(ResourceProvider* resource_provider) | 26 VideoResourceUpdater::VideoResourceUpdater(ResourceProvider* resource_provider) |
27 : resource_provider_(resource_provider) { | 27 : resource_provider_(resource_provider) { |
28 } | 28 } |
29 | 29 |
30 VideoResourceUpdater::~VideoResourceUpdater() {} | 30 VideoResourceUpdater::~VideoResourceUpdater() { |
| 31 while (!recycled_resources_.empty()) { |
| 32 resource_provider_->DeleteResource(recycled_resources_.back().resource_id); |
| 33 recycled_resources_.pop_back(); |
| 34 } |
| 35 } |
31 | 36 |
32 bool VideoResourceUpdater::VerifyFrame( | 37 bool VideoResourceUpdater::VerifyFrame( |
33 const scoped_refptr<media::VideoFrame>& video_frame) { | 38 const scoped_refptr<media::VideoFrame>& video_frame) { |
34 // If these fail, we'll have to add logic that handles offset bitmap/texture | 39 // If these fail, we'll have to add logic that handles offset bitmap/texture |
35 // UVs. For now, just expect (0, 0) offset, since all our decoders so far | 40 // UVs. For now, just expect (0, 0) offset, since all our decoders so far |
36 // don't offset. | 41 // don't offset. |
37 DCHECK_EQ(video_frame->visible_rect().x(), 0); | 42 DCHECK_EQ(video_frame->visible_rect().x(), 0); |
38 DCHECK_EQ(video_frame->visible_rect().y(), 0); | 43 DCHECK_EQ(video_frame->visible_rect().y(), 0); |
39 | 44 |
40 switch (video_frame->format()) { | 45 switch (video_frame->format()) { |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
83 case media::VideoFrame::HOLE: | 88 case media::VideoFrame::HOLE: |
84 #endif | 89 #endif |
85 NOTREACHED(); | 90 NOTREACHED(); |
86 } | 91 } |
87 } | 92 } |
88 | 93 |
89 DCHECK_EQ(output_resource_format, static_cast<unsigned>(kRGBResourceFormat)); | 94 DCHECK_EQ(output_resource_format, static_cast<unsigned>(kRGBResourceFormat)); |
90 return coded_size; | 95 return coded_size; |
91 } | 96 } |
92 | 97 |
93 static void ReleaseResource(ResourceProvider* resource_provider, | |
94 ResourceProvider::ResourceId resource_id, | |
95 unsigned sync_point) { | |
96 resource_provider->DeleteResource(resource_id); | |
97 } | |
98 | |
99 VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes( | 98 VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes( |
100 const scoped_refptr<media::VideoFrame>& video_frame) { | 99 const scoped_refptr<media::VideoFrame>& video_frame) { |
101 if (!VerifyFrame(video_frame)) | 100 if (!VerifyFrame(video_frame)) |
102 return VideoFrameExternalResources(); | 101 return VideoFrameExternalResources(); |
103 | 102 |
104 media::VideoFrame::Format input_frame_format = video_frame->format(); | 103 media::VideoFrame::Format input_frame_format = video_frame->format(); |
105 | 104 |
106 #if defined(GOOGLE_TV) | 105 #if defined(GOOGLE_TV) |
107 if (input_frame_format == media::VideoFrame::HOLE) { | 106 if (input_frame_format == media::VideoFrame::HOLE) { |
108 VideoFrameExternalResources external_resources; | 107 VideoFrameExternalResources external_resources; |
(...skipping 19 matching lines...) Expand all Loading... |
128 // Obviously, this is suboptimal and should be addressed once ubercompositor | 127 // Obviously, this is suboptimal and should be addressed once ubercompositor |
129 // starts shaping up. | 128 // starts shaping up. |
130 if (software_compositor) { | 129 if (software_compositor) { |
131 output_resource_format = kRGBResourceFormat; | 130 output_resource_format = kRGBResourceFormat; |
132 output_plane_count = 1; | 131 output_plane_count = 1; |
133 } | 132 } |
134 | 133 |
135 int max_resource_size = resource_provider_->max_texture_size(); | 134 int max_resource_size = resource_provider_->max_texture_size(); |
136 gfx::Size coded_frame_size = video_frame->coded_size(); | 135 gfx::Size coded_frame_size = video_frame->coded_size(); |
137 | 136 |
138 ResourceProvider::ResourceIdArray plane_resources; | 137 std::vector<PlaneResource> plane_resources; |
139 bool allocation_success = true; | 138 bool allocation_success = true; |
140 | 139 |
141 for (size_t i = 0; i < output_plane_count; ++i) { | 140 for (size_t i = 0; i < output_plane_count; ++i) { |
142 gfx::Size plane_size = | 141 gfx::Size output_plane_resource_size = |
143 SoftwarePlaneDimension(input_frame_format, | 142 SoftwarePlaneDimension(input_frame_format, |
144 coded_frame_size, | 143 coded_frame_size, |
145 output_resource_format, | 144 output_resource_format, |
146 i); | 145 i); |
147 if (plane_size.IsEmpty() || | 146 if (output_plane_resource_size.IsEmpty() || |
148 plane_size.width() > max_resource_size || | 147 output_plane_resource_size.width() > max_resource_size || |
149 plane_size.height() > max_resource_size) { | 148 output_plane_resource_size.height() > max_resource_size) { |
150 allocation_success = false; | 149 allocation_success = false; |
151 break; | 150 break; |
152 } | 151 } |
153 | 152 |
154 // TODO(danakj): Could recycle resources that we previously allocated and | 153 ResourceProvider::ResourceId resource_id = 0; |
155 // were returned to us. | 154 unsigned sync_point = 0; |
156 ResourceProvider::ResourceId resource_id = | 155 |
157 resource_provider_->CreateResource(plane_size, | 156 // Try recycle a previously-allocated resource. |
158 output_resource_format, | 157 for (size_t i = 0; i < recycled_resources_.size(); ++i) { |
159 ResourceProvider::TextureUsageAny); | 158 if (recycled_resources_[i].resource_format == output_resource_format && |
| 159 recycled_resources_[i].resource_size == output_plane_resource_size) { |
| 160 resource_id = recycled_resources_[i].resource_id; |
| 161 sync_point = recycled_resources_[i].sync_point; |
| 162 recycled_resources_.erase(recycled_resources_.begin() + i); |
| 163 break; |
| 164 } |
| 165 } |
| 166 |
| 167 if (resource_id == 0) { |
| 168 // TODO(danakj): Abstract out hw/sw resource create/delete from |
| 169 // ResourceProvider and stop using ResourceProvider in this class. |
| 170 resource_id = |
| 171 resource_provider_->CreateResource(output_plane_resource_size, |
| 172 output_resource_format, |
| 173 ResourceProvider::TextureUsageAny); |
| 174 } |
| 175 |
160 if (resource_id == 0) { | 176 if (resource_id == 0) { |
161 allocation_success = false; | 177 allocation_success = false; |
162 break; | 178 break; |
163 } | 179 } |
164 | 180 |
165 plane_resources.push_back(resource_id); | 181 plane_resources.push_back(PlaneResource(resource_id, |
| 182 output_plane_resource_size, |
| 183 output_resource_format, |
| 184 sync_point)); |
166 } | 185 } |
167 | 186 |
168 if (!allocation_success) { | 187 if (!allocation_success) { |
169 for (size_t i = 0; i < plane_resources.size(); ++i) | 188 for (size_t i = 0; i < plane_resources.size(); ++i) |
170 resource_provider_->DeleteResource(plane_resources[i]); | 189 resource_provider_->DeleteResource(plane_resources[i].resource_id); |
171 return VideoFrameExternalResources(); | 190 return VideoFrameExternalResources(); |
172 } | 191 } |
173 | 192 |
174 VideoFrameExternalResources external_resources; | 193 VideoFrameExternalResources external_resources; |
175 | 194 |
176 if (software_compositor) { | 195 if (software_compositor) { |
177 DCHECK_EQ(output_resource_format, kRGBResourceFormat); | |
178 DCHECK_EQ(plane_resources.size(), 1u); | 196 DCHECK_EQ(plane_resources.size(), 1u); |
| 197 DCHECK_EQ(plane_resources[0].resource_format, kRGBResourceFormat); |
| 198 DCHECK_EQ(plane_resources[0].sync_point, 0u); |
179 | 199 |
180 if (!video_renderer_) | 200 if (!video_renderer_) |
181 video_renderer_.reset(new media::SkCanvasVideoRenderer); | 201 video_renderer_.reset(new media::SkCanvasVideoRenderer); |
182 | 202 |
183 { | 203 { |
184 ResourceProvider::ScopedWriteLockSoftware lock( | 204 ResourceProvider::ScopedWriteLockSoftware lock( |
185 resource_provider_, plane_resources[0]); | 205 resource_provider_, plane_resources[0].resource_id); |
186 video_renderer_->Paint(video_frame, | 206 video_renderer_->Paint(video_frame, |
187 lock.sk_canvas(), | 207 lock.sk_canvas(), |
188 video_frame->visible_rect(), | 208 video_frame->visible_rect(), |
189 0xff); | 209 0xff); |
190 } | 210 } |
191 | 211 |
192 // In software mode, the resource provider won't be lost. Soon this callback | 212 // In software mode, the resource provider won't be lost. Soon this callback |
193 // will be called directly from the resource provider, same as 3d | 213 // will be called directly from the resource provider, same as 3d |
194 // compositing mode, so this raw unretained resource_provider will always | 214 // compositing mode, so this raw unretained resource_provider will always |
195 // be valid when the callback is fired. | 215 // be valid when the callback is fired. |
196 TextureMailbox::ReleaseCallback callback_to_free_resource = | 216 TextureMailbox::ReleaseCallback callback_to_free_resource = |
197 base::Bind(&ReleaseResource, | 217 base::Bind(&RecycleResource, |
| 218 AsWeakPtr(), |
198 base::Unretained(resource_provider_), | 219 base::Unretained(resource_provider_), |
199 plane_resources[0]); | 220 plane_resources[0].resource_id, |
200 external_resources.software_resources.push_back(plane_resources[0]); | 221 plane_resources[0].resource_size, |
| 222 plane_resources[0].resource_format, |
| 223 gpu::Mailbox()); |
| 224 external_resources.software_resources.push_back( |
| 225 plane_resources[0].resource_id); |
201 external_resources.software_release_callback = callback_to_free_resource; | 226 external_resources.software_release_callback = callback_to_free_resource; |
202 | 227 |
203 external_resources.type = VideoFrameExternalResources::SOFTWARE_RESOURCE; | 228 external_resources.type = VideoFrameExternalResources::SOFTWARE_RESOURCE; |
204 return external_resources; | 229 return external_resources; |
205 } | 230 } |
206 | 231 |
207 DCHECK_EQ(output_resource_format, | |
208 static_cast<unsigned>(kYUVResourceFormat)); | |
209 | |
210 WebKit::WebGraphicsContext3D* context = | 232 WebKit::WebGraphicsContext3D* context = |
211 resource_provider_->GraphicsContext3D(); | 233 resource_provider_->GraphicsContext3D(); |
212 DCHECK(context); | 234 DCHECK(context); |
213 | 235 |
214 for (size_t plane = 0; plane < plane_resources.size(); ++plane) { | 236 for (size_t i = 0; i < plane_resources.size(); ++i) { |
215 // Update each plane's resource id with its content. | 237 // Update each plane's resource id with its content. |
216 ResourceProvider::ResourceId output_plane_resource_id = | 238 DCHECK_EQ(plane_resources[i].resource_format, |
217 plane_resources[plane]; | 239 static_cast<unsigned>(kYUVResourceFormat)); |
218 gfx::Size plane_size = | |
219 SoftwarePlaneDimension(input_frame_format, | |
220 coded_frame_size, | |
221 output_resource_format, | |
222 plane); | |
223 const uint8_t* input_plane_pixels = video_frame->data(plane); | |
224 | 240 |
225 gfx::Rect image_rect( | 241 const uint8_t* input_plane_pixels = video_frame->data(i); |
226 0, 0, video_frame->stride(plane), plane_size.height()); | 242 |
227 gfx::Rect source_rect(plane_size); | 243 gfx::Rect image_rect(0, |
228 resource_provider_->SetPixels(output_plane_resource_id, | 244 0, |
| 245 video_frame->stride(i), |
| 246 plane_resources[i].resource_size.height()); |
| 247 gfx::Rect source_rect(plane_resources[i].resource_size); |
| 248 resource_provider_->SetPixels(plane_resources[i].resource_id, |
229 input_plane_pixels, | 249 input_plane_pixels, |
230 image_rect, | 250 image_rect, |
231 source_rect, | 251 source_rect, |
232 gfx::Vector2d()); | 252 gfx::Vector2d()); |
233 | 253 |
234 gpu::Mailbox mailbox; | 254 gpu::Mailbox mailbox; |
235 { | 255 { |
236 ResourceProvider::ScopedWriteLockGL lock( | 256 ResourceProvider::ScopedWriteLockGL lock( |
237 resource_provider_, output_plane_resource_id); | 257 resource_provider_, plane_resources[i].resource_id); |
238 | 258 |
239 GLC(context, context->genMailboxCHROMIUM(mailbox.name)); | 259 GLC(context, context->genMailboxCHROMIUM(mailbox.name)); |
240 GLC(context, context->bindTexture(GL_TEXTURE_2D, lock.texture_id())); | 260 GLC(context, context->bindTexture(GL_TEXTURE_2D, lock.texture_id())); |
241 GLC(context, context->produceTextureCHROMIUM(GL_TEXTURE_2D, | 261 GLC(context, context->produceTextureCHROMIUM(GL_TEXTURE_2D, |
242 mailbox.name)); | 262 mailbox.name)); |
243 GLC(context, context->bindTexture(GL_TEXTURE_2D, 0)); | 263 GLC(context, context->bindTexture(GL_TEXTURE_2D, 0)); |
244 } | 264 } |
245 | 265 |
246 // This callback is called by the resource provider itself, so it's okay to | 266 // This callback is called by the resource provider itself, so it's okay to |
247 // use an unretained raw pointer here. | 267 // use an unretained raw pointer here. |
248 TextureMailbox::ReleaseCallback callback_to_free_resource = | 268 TextureMailbox::ReleaseCallback callback_to_free_resource = |
249 base::Bind(&ReleaseResource, | 269 base::Bind(&RecycleResource, |
| 270 AsWeakPtr(), |
250 base::Unretained(resource_provider_), | 271 base::Unretained(resource_provider_), |
251 output_plane_resource_id); | 272 plane_resources[i].resource_id, |
| 273 plane_resources[i].resource_size, |
| 274 plane_resources[i].resource_format, |
| 275 mailbox); |
252 external_resources.mailboxes.push_back( | 276 external_resources.mailboxes.push_back( |
253 TextureMailbox(mailbox, callback_to_free_resource)); | 277 TextureMailbox(mailbox, |
| 278 callback_to_free_resource, |
| 279 plane_resources[i].sync_point)); |
254 } | 280 } |
255 | 281 |
256 external_resources.type = VideoFrameExternalResources::YUV_RESOURCE; | 282 external_resources.type = VideoFrameExternalResources::YUV_RESOURCE; |
257 return external_resources; | 283 return external_resources; |
258 } | 284 } |
259 | 285 |
260 VideoFrameExternalResources VideoResourceUpdater::CreateForHardwarePlanes( | 286 VideoFrameExternalResources VideoResourceUpdater::CreateForHardwarePlanes( |
261 const scoped_refptr<media::VideoFrame>& video_frame, | 287 const scoped_refptr<media::VideoFrame>& video_frame, |
262 const TextureMailbox::ReleaseCallback& release_callback) { | 288 const TextureMailbox::ReleaseCallback& release_callback) { |
263 if (!VerifyFrame(video_frame)) | 289 if (!VerifyFrame(video_frame)) |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
316 gpu::Mailbox mailbox, | 342 gpu::Mailbox mailbox, |
317 unsigned sync_point) { | 343 unsigned sync_point) { |
318 WebKit::WebGraphicsContext3D* context = | 344 WebKit::WebGraphicsContext3D* context = |
319 resource_provider->GraphicsContext3D(); | 345 resource_provider->GraphicsContext3D(); |
320 GLC(context, context->bindTexture(GL_TEXTURE_2D, texture_id)); | 346 GLC(context, context->bindTexture(GL_TEXTURE_2D, texture_id)); |
321 GLC(context, context->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name)); | 347 GLC(context, context->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name)); |
322 GLC(context, context->bindTexture(GL_TEXTURE_2D, 0)); | 348 GLC(context, context->bindTexture(GL_TEXTURE_2D, 0)); |
323 callback.Run(sync_point); | 349 callback.Run(sync_point); |
324 } | 350 } |
325 | 351 |
| 352 // static |
| 353 void VideoResourceUpdater::RecycleResource( |
| 354 base::WeakPtr<VideoResourceUpdater> updater, |
| 355 ResourceProvider* resource_provider, |
| 356 unsigned resource_id, |
| 357 gfx::Size resource_size, |
| 358 unsigned resource_format, |
| 359 gpu::Mailbox mailbox, |
| 360 unsigned sync_point) { |
| 361 WebKit::WebGraphicsContext3D* context = |
| 362 resource_provider->GraphicsContext3D(); |
| 363 if (context) { |
| 364 ResourceProvider::ScopedWriteLockGL lock(resource_provider, resource_id); |
| 365 GLC(context, context->bindTexture(GL_TEXTURE_2D, lock.texture_id())); |
| 366 GLC(context, context->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name)); |
| 367 GLC(context, context->bindTexture(GL_TEXTURE_2D, 0)); |
| 368 } |
| 369 |
| 370 if (!updater) { |
| 371 resource_provider->DeleteResource(resource_id); |
| 372 return; |
| 373 } |
| 374 |
| 375 // Drop recycled resources that are the wrong format. |
| 376 while (!updater->recycled_resources_.empty() && |
| 377 updater->recycled_resources_.back().resource_format != |
| 378 resource_format) { |
| 379 resource_provider->DeleteResource( |
| 380 updater->recycled_resources_.back().resource_id); |
| 381 updater->recycled_resources_.pop_back(); |
| 382 } |
| 383 |
| 384 PlaneResource recycled_resource(resource_id, |
| 385 resource_size, |
| 386 resource_format, |
| 387 sync_point); |
| 388 updater->recycled_resources_.push_back(recycled_resource); |
| 389 } |
| 390 |
326 } // namespace cc | 391 } // namespace cc |
OLD | NEW |