Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(386)

Side by Side Diff: content/common/gpu/media/vaapi_picture_provider.cc

Issue 490233002: VaapiVideoAccelerator: make Vaapi accelerator work with ozone (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Reenable Ozone path Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 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 "content/common/gpu/media/vaapi_picture_provider.h"
6
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "ui/gl/gl_bindings.h"
10 #include "ui/gl/gl_image.h"
11 #if defined(USE_X11)
12 #include "third_party/libva/va/va_x11.h"
13 #include "ui/gl/gl_context_glx.h"
14 #else
15 #include <gbm.h>
spang 2014/09/05 20:45:46 Remove gbm #include.
16 #include "third_party/libva/va/drm/va_drm.h"
17 #include "third_party/libva/va/va_drmcommon.h"
18 #include "ui/gl/gl_image_egl.h"
19 #include "ui/ozone/public/native_pixmap.h"
20 #include "ui/ozone/public/ozone_platform.h"
21 #include "ui/ozone/public/surface_factory_ozone.h"
22 #include <va/va_vpp.h>
23 #endif // USE_X11
24 #include "ui/gl/scoped_binders.h"
25
26 #define LOG_VA_ERROR_AND_RETURN(input, err_msg, output_code) \
27 do { \
28 VAStatus va_status = input; \
29 if (va_status != VA_STATUS_SUCCESS) { \
30 DVLOG(1) << err_msg << " : " << va_status; \
31 output_code; \
32 return false; \
33 } \
34 } while (0)
35
36 namespace content {
37
38 namespace {
39
40 #if defined(USE_X11)
41
42 class TFPPicture;
43
44 class X11VaapiPictureProvider : public VaapiPictureProvider {
45 public:
46 X11VaapiPictureProvider(
47 VADisplay va_display,
48 gfx::GLContextGLX* glx_context,
49 const base::Callback<bool(void)> make_context_current);
50 virtual ~X11VaapiPictureProvider();
51
52 virtual scoped_ptr<VaapiPictureProvider::Picture> CreatePicture(
53 int32 picture_buffer_id,
54 uint32 texture_id,
55 const gfx::Size& size) OVERRIDE;
56
57 void DestroyPicture(TFPPicture* tfp_picture);
58
59 virtual bool PutSurfaceIntoPicture(
60 VASurfaceID va_surface_id,
61 VaapiPictureProvider::Picture* picture) OVERRIDE;
62
63 virtual bool Initialize() OVERRIDE;
64
65 private:
66
67 bool BindPicture(TFPPicture* picture);
68
69 gfx::GLContextGLX* glx_context_;
70 base::Callback<bool(void)> make_context_current_;
71
72 Display* x_display_;
73 GLXFBConfig fb_config_;
74
75 VADisplay va_display_;
76 };
77
78 class TFPPicture : public VaapiPictureProvider::Picture {
79 public:
80 TFPPicture(X11VaapiPictureProvider* provider,
81 int32 picture_buffer_id,
82 uint32 texture_id,
83 const gfx::Size& size,
84 Pixmap x_pixmap,
85 GLXPixmap glx_pixmap)
86 : Picture(picture_buffer_id, texture_id, size),
87 provider_(provider),
88 x_pixmap_(x_pixmap),
89 glx_pixmap_(glx_pixmap) {}
90 virtual ~TFPPicture() { provider_->DestroyPicture(this); }
91
92 Pixmap x_pixmap() const { return x_pixmap_; }
93 GLXPixmap glx_pixmap() const { return glx_pixmap_; }
94
95 private:
96 X11VaapiPictureProvider* provider_;
97 Pixmap x_pixmap_;
98 GLXPixmap glx_pixmap_;
99 };
100
101 class XFreeDeleter {
102 public:
103 void operator()(void* x) const { ::XFree(x); }
104 };
105
106 X11VaapiPictureProvider::X11VaapiPictureProvider(
107 VADisplay va_display,
108 gfx::GLContextGLX* glx_context,
109 const base::Callback<bool(void)> make_context_current)
110 : glx_context_(glx_context),
111 make_context_current_(make_context_current),
112 x_display_(glx_context_->display()),
113 va_display_(va_display) {
114 }
115
116 X11VaapiPictureProvider::~X11VaapiPictureProvider() {
117 }
118
119 scoped_ptr<VaapiPictureProvider::Picture>
120 X11VaapiPictureProvider::CreatePicture(int32 picture_buffer_id,
121 uint32 texture_id,
122 const gfx::Size& size) {
123 scoped_ptr<VaapiPictureProvider::Picture> picture;
124
125 if (!make_context_current_.Run())
126 return picture.Pass();
127
128 XWindowAttributes win_attr;
129 int screen = DefaultScreen(x_display_);
130 XGetWindowAttributes(x_display_, RootWindow(x_display_, screen), &win_attr);
131 // TODO(posciak): pass the depth required by libva, not the RootWindow's
132 // depth
133 Pixmap x_pixmap = XCreatePixmap(x_display_,
134 RootWindow(x_display_, screen),
135 size.width(),
136 size.height(),
137 win_attr.depth);
138 if (!x_pixmap) {
139 DVLOG(1) << "Failed creating an X Pixmap for TFP";
140 return picture.Pass();
141 }
142
143 static const int pixmap_attr[] = {
144 GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, GLX_TEXTURE_FORMAT_EXT,
145 GLX_TEXTURE_FORMAT_RGB_EXT, GL_NONE,
146 };
147
148 GLXPixmap glx_pixmap =
149 glXCreatePixmap(x_display_, fb_config_, x_pixmap, pixmap_attr);
150 if (!glx_pixmap) {
151 // x_pixmap_ will be freed in the destructor.
152 DVLOG(1) << "Failed creating a GLX Pixmap for TFP";
153 XFreePixmap(x_display_, x_pixmap);
154 return picture.Pass();
155 }
156
157 picture.reset(new TFPPicture(this,
158 picture_buffer_id,
159 texture_id,
160 size,
161 x_pixmap,
162 glx_pixmap));
163
164 return picture.Pass();
165 }
166
167 void X11VaapiPictureProvider::DestroyPicture(TFPPicture* tfp_picture) {
168 // Unbind surface from texture and deallocate resources.
169 if (tfp_picture->glx_pixmap() && make_context_current_.Run()) {
170 glXReleaseTexImageEXT(x_display_,
171 tfp_picture->glx_pixmap(),
172 GLX_FRONT_LEFT_EXT);
173 glXDestroyPixmap(x_display_, tfp_picture->glx_pixmap());
174 }
175
176 if (tfp_picture->x_pixmap())
177 XFreePixmap(x_display_, tfp_picture->x_pixmap());
178 XSync(x_display_, False); // Needed to work around buggy vdpau-driver.
179 }
180
181 bool X11VaapiPictureProvider::PutSurfaceIntoPicture(
182 VASurfaceID va_surface_id,
183 VaapiPictureProvider::Picture* picture) {
184 TFPPicture* tfp_picture = static_cast<TFPPicture*>(picture);
185 const gfx::Size& size = tfp_picture->size();
186
187 if (!BindPicture(tfp_picture))
188 return false;
189
190 LOG_VA_ERROR_AND_RETURN(vaPutSurface(va_display_,
191 va_surface_id,
192 tfp_picture->x_pixmap(),
193 0, 0,
194 size.width(),
195 size.height(),
196 0, 0,
197 size.width(),
198 size.height(),
199 NULL,
200 0, 0),
201 "Couldn't put surface into picture",);
202 return true;
203 }
204
205 bool X11VaapiPictureProvider::Initialize(){
206 if (!make_context_current_.Run()) {
207 DVLOG(1) << "Couldn't make context current";
208 return false;
209 }
210
211 const int fbconfig_attr[] = {
212 GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
213 GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT,
214 GLX_BIND_TO_TEXTURE_RGB_EXT, GL_TRUE,
215 GLX_Y_INVERTED_EXT, GL_TRUE,
216 GL_NONE,
217 };
218
219 int num_fbconfigs;
220 scoped_ptr<GLXFBConfig, XFreeDeleter> glx_fb_configs(glXChooseFBConfig(
221 x_display_, DefaultScreen(x_display_), fbconfig_attr, &num_fbconfigs));
222
223 if (!glx_fb_configs) {
224 DVLOG(1) << "Couldn't get glx configs";
225 return false;
226 }
227 if (!num_fbconfigs) {
228 DVLOG(1) << "Couldn't get at least a glx config";
229 return false;
230 }
231
232 fb_config_ = glx_fb_configs.get()[0];
233 return true;
234 }
235
236 bool X11VaapiPictureProvider::BindPicture(TFPPicture* tfp_picture) {
237 if (!make_context_current_.Run()) {
238 DVLOG(1) << "Failed making gl context current";
239 return false;
240 }
241
242 gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_2D,
243 tfp_picture->texture_id());
244 glXBindTexImageEXT(x_display_, tfp_picture->glx_pixmap(),
245 GLX_FRONT_LEFT_EXT, NULL);
246
247 return true;
248 }
249
250 #else
251
252 class GbmPicture;
253
254 class GbmVaapiPictureProvider : public VaapiPictureProvider {
spang 2014/09/05 20:45:46 s/Gbm/Drm/
255 public:
256 GbmVaapiPictureProvider(
257 VADisplay va_display,
258 const base::Callback<bool(void)> make_context_current);
259 virtual ~GbmVaapiPictureProvider();
260
261 virtual scoped_ptr<VaapiPictureProvider::Picture> CreatePicture(
262 int32 picture_buffer_id,
263 uint32 texture_id,
264 const gfx::Size& size) OVERRIDE;
265
266 void DestroyPicture(GbmPicture* gbm_picture);
267
268 virtual bool PutSurfaceIntoPicture(
269 VASurfaceID va_surface_id,
270 VaapiPictureProvider::Picture* picture) OVERRIDE;
271
272 virtual bool SetCodedSurfacesSize(const gfx::Size& size) OVERRIDE;
273
274 virtual bool Initialize() OVERRIDE;
275
276 private:
277 bool InitializeVpp(const gfx::Size& size);
278
279 bool IsVppInitialized();
280
281 void DeinitializeVpp();
282
283 base::Callback<bool(void)> make_context_current_;
284
285 VADisplay va_display_;
286
287 VAConfigID vpp_config_;
288 VAContextID vpp_context_;
289 VABufferID vpp_buffer_;
290
291 gfx::Size coded_picture_size_;
292 };
293
294 class GbmPicture : public VaapiPictureProvider::Picture {
spang 2014/09/05 20:45:46 s/Gbm/Drm/
295 public:
296 GbmPicture(GbmVaapiPictureProvider* provider,
297 int32 picture_buffer_id,
298 uint32 texture_id,
299 const gfx::Size& size,
300 VASurfaceID va_surface,
301 scoped_refptr<ui::NativePixmap> pixmap,
302 scoped_refptr<gfx::GLImage> gl_image)
303 : Picture(picture_buffer_id, texture_id, size),
304 provider_(provider),
305 va_surface_(va_surface),
306 pixmap_(pixmap),
307 gl_image_(gl_image) {}
308 virtual ~GbmPicture() {
309 provider_->DestroyPicture(this);
310 }
311
312 scoped_refptr<gfx::GLImage> gl_image() const { return gl_image_; }
313 VASurfaceID va_surface() const { return va_surface_; }
314
315 private:
316 GbmVaapiPictureProvider* provider_;
317 VASurfaceID va_surface_;
318 scoped_refptr<ui::NativePixmap> pixmap_;
319 scoped_refptr<gfx::GLImage> gl_image_;
320 };
321
322 GbmVaapiPictureProvider::GbmVaapiPictureProvider(
323 VADisplay va_display,
324 const base::Callback<bool(void)> make_context_current)
325 : make_context_current_(make_context_current),
326 va_display_(va_display),
327 vpp_config_(VA_INVALID_ID),
328 vpp_context_(VA_INVALID_ID),
329 vpp_buffer_(VA_INVALID_ID) {
330 }
331
332 GbmVaapiPictureProvider::~GbmVaapiPictureProvider() {
333 DeinitializeVpp();
334 }
335
336 scoped_ptr<VaapiPictureProvider::Picture>
337 GbmVaapiPictureProvider::CreatePicture(int32 picture_buffer_id,
338 uint32 texture_id,
339 const gfx::Size& size) {
340 VASurfaceAttrib va_attribs[2];
341 VASurfaceAttribExternalBuffers va_attrib_extbuf;
342
343 ui::OzonePlatform* platform = ui::OzonePlatform::GetInstance();
344 ui::SurfaceFactoryOzone* factory = platform->GetSurfaceFactoryOzone();
345
346 scoped_refptr<ui::NativePixmap> pixmap =
347 factory->CreateNativePixmap(size, ui::SurfaceFactoryOzone::RGBA_8888);
348 struct gbm_bo* bo = static_cast<struct gbm_bo*>(pixmap->GetEGLClientBuffer());
349 unsigned long buffer_fd = pixmap->GetDmaBufFd();
350 VASurfaceID va_surface;
351
352 va_attrib_extbuf.pixel_format = VA_FOURCC_BGRX;
353 va_attrib_extbuf.width = size.width();
354 va_attrib_extbuf.height = size.height();
355 va_attrib_extbuf.data_size = size.height() * gbm_bo_get_stride (bo);
spang 2014/09/05 20:45:46 Move these gbm calls into GbmPixmap & add a virtua
356 va_attrib_extbuf.num_planes = 1;
357 va_attrib_extbuf.pitches[0] = gbm_bo_get_stride (bo);
358 va_attrib_extbuf.offsets[0] = 0;
359 va_attrib_extbuf.buffers = &buffer_fd;
360 va_attrib_extbuf.num_buffers = 1;
361 va_attrib_extbuf.flags = 0;
362 va_attrib_extbuf.private_data = NULL;
363
364 va_attribs[0].type = VASurfaceAttribMemoryType;
365 va_attribs[0].flags = VA_SURFACE_ATTRIB_SETTABLE;
366 va_attribs[0].value.type = VAGenericValueTypeInteger;
367 va_attribs[0].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
368
369 va_attribs[1].type = VASurfaceAttribExternalBufferDescriptor;
370 va_attribs[1].flags = VA_SURFACE_ATTRIB_SETTABLE;
371 va_attribs[1].value.type = VAGenericValueTypePointer;
372 va_attribs[1].value.value.p = &va_attrib_extbuf;
373
374 VAStatus status = vaCreateSurfaces(va_display_,
375 VA_RT_FORMAT_RGB32,
376 size.width(),
377 size.height(),
378 &va_surface,
379 1,
380 va_attribs,
381 arraysize(va_attribs));
382
383 scoped_ptr<Picture> picture;
384
385 if (status == VA_STATUS_SUCCESS) {
386 if (!make_context_current_.Run())
387 return picture.Pass();
388
389 EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
390 scoped_refptr<gfx::GLImageEGL> gl_image(new gfx::GLImageEGL(size));
391 gl_image->Initialize(
392 EGL_NATIVE_PIXMAP_KHR,
393 pixmap->GetEGLClientBuffer(),
394 attrs);
395
396
397 if (static_cast<int>(glGetError()) != GL_NO_ERROR)
398 return picture.Pass();
399
400 picture.reset(new GbmPicture(this,
401 picture_buffer_id,
402 texture_id,
403 size,
404 va_surface,
405 pixmap,
406 gl_image));
407 }
408
409 return picture.Pass();
410 }
411
412 void GbmVaapiPictureProvider::DestroyPicture(GbmPicture* gbm_picture) {
413 VASurfaceID va_surface = gbm_picture->va_surface();
414
415 if (!make_context_current_.Run())
416 return;
417
418 // ReleaseTexImage on a GLImageEGL does nothing, do deassociate
419 // the renderer texture from the image, just set the storage of
420 // that texture to NULL
421 gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_2D,
422 gbm_picture->texture_id());
423 glTexImage2D(GL_TEXTURE_2D,
424 0,
425 GL_RGBA,
426 gbm_picture->size().width(),
427 gbm_picture->size().height(),
428 0,
429 GL_RGBA,
430 GL_UNSIGNED_BYTE,
431 NULL);
432
433 gbm_picture->gl_image()->Destroy(true);
434
435 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR);
436
437 vaDestroySurfaces(va_display_, &va_surface, 1);
438 }
439
440 bool GbmVaapiPictureProvider::PutSurfaceIntoPicture(
441 VASurfaceID va_surface_id,
442 VaapiPictureProvider::Picture* picture) {
443 GbmPicture* gbm_picture = static_cast<GbmPicture*>(picture);
444 VAProcPipelineParameterBuffer* pipeline_param;
445 VARectangle input_region, output_region;
446
447 DCHECK(IsVppInitialized());
448
449 LOG_VA_ERROR_AND_RETURN(vaMapBuffer(va_display_,
450 vpp_buffer_,
451 (void**)&pipeline_param),
452 "Couldn't map buffer",);
453
454 memset(pipeline_param, 0, sizeof *pipeline_param);
455
456 input_region.x = input_region.y = 0;
457 input_region.width = coded_picture_size_.width();
458 input_region.height = coded_picture_size_.height();
459 pipeline_param->surface_region = &input_region;
460 pipeline_param->surface = va_surface_id;
461 pipeline_param->surface_color_standard = VAProcColorStandardNone;
462
463 output_region.x = output_region.y = 0;
464 output_region.width = gbm_picture->size().width();
465 output_region.height = gbm_picture->size().height();
466 pipeline_param->output_region = &output_region;
467 pipeline_param->output_background_color = 0xff000000;
468 pipeline_param->output_color_standard = VAProcColorStandardNone;
469
470 LOG_VA_ERROR_AND_RETURN(vaUnmapBuffer(va_display_, vpp_buffer_),
471 "Couldn't unmap buffer",);
472
473 LOG_VA_ERROR_AND_RETURN(vaBeginPicture(va_display_,
474 vpp_context_,
475 gbm_picture->va_surface()),
476 "Couldn't begin picture",);
477
478 LOG_VA_ERROR_AND_RETURN(vaRenderPicture(va_display_,
479 vpp_context_,
480 &vpp_buffer_, 1),
481 "Couldn't render picture",);
482
483 LOG_VA_ERROR_AND_RETURN(vaEndPicture(va_display_, vpp_context_),
484 "Couldn't end picture", );
485
486 if (!make_context_current_.Run())
487 return VA_STATUS_ERROR_OPERATION_FAILED;
488
489 gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_2D,
490 gbm_picture->texture_id());
491 gbm_picture->gl_image()->BindTexImage(GL_TEXTURE_2D);
492
493 if (static_cast<int>(glGetError()) != GL_NO_ERROR)
494 return false;
495
496 return true;
497 }
498
499 bool GbmVaapiPictureProvider::SetCodedSurfacesSize(const gfx::Size& size) {
500 DeinitializeVpp();
501 return InitializeVpp(size);
502 }
503
504
505 bool GbmVaapiPictureProvider::Initialize() {
506 return true;
507 }
508
509 bool GbmVaapiPictureProvider::InitializeVpp(const gfx::Size& size) {
510 LOG_VA_ERROR_AND_RETURN(vaCreateConfig(va_display_,
511 VAProfileNone,
512 VAEntrypointVideoProc,
513 NULL,
514 0,
515 &vpp_config_),
516 "Couldn't create config",);
517
518 LOG_VA_ERROR_AND_RETURN(vaCreateContext(va_display_,
519 vpp_config_,
520 size.width(),
521 size.height(),
522 0,
523 NULL,
524 0,
525 &vpp_context_),
526 "Couldn't create context",
527 DeinitializeVpp());
528
529 LOG_VA_ERROR_AND_RETURN(vaCreateBuffer(va_display_,
530 vpp_context_,
531 VAProcPipelineParameterBufferType,
532 sizeof(VAProcPipelineParameterBuffer),
533 1,
534 NULL,
535 &vpp_buffer_),
536 "Couldn't create buffer",
537 DeinitializeVpp());
538
539 coded_picture_size_ = size;
540
541 return true;
542 }
543
544 bool GbmVaapiPictureProvider::IsVppInitialized() {
545 return vpp_buffer_ != VA_INVALID_ID;
546 }
547
548 void GbmVaapiPictureProvider::DeinitializeVpp() {
549 if (vpp_buffer_ != VA_INVALID_ID) {
550 vaDestroyBuffer(va_display_, vpp_buffer_);
551 vpp_buffer_ = VA_INVALID_ID;
552 }
553 if (vpp_context_ != VA_INVALID_ID) {
554 vaDestroyContext(va_display_, vpp_context_);
555 vpp_context_ = VA_INVALID_ID;
556 }
557 if (vpp_config_ != VA_INVALID_ID) {
558 vaDestroyConfig(va_display_, vpp_config_);
559 vpp_config_ = VA_INVALID_ID;
560 }
561 }
562
563 #endif // USE_X11
564
565 } // namespace
566
567
568 scoped_ptr<VaapiPictureProvider> VaapiPictureProvider::Create(
569 VADisplay va_display,
570 gfx::GLContext* gl_context,
571 const base::Callback<bool(void)> make_context_current) {
572 scoped_ptr<VaapiPictureProvider> backend;
573
574 #if defined(USE_X11)
575 backend.reset(new X11VaapiPictureProvider(
576 va_display,
577 static_cast<gfx::GLContextGLX*>(gl_context),
578 make_context_current));
579 #else
580 backend.reset(new GbmVaapiPictureProvider(va_display,
581 make_context_current));
582 #endif // USE_X11
583
584 if (!backend->Initialize())
585 backend.reset();
586
587 return backend.Pass();
588 }
589
590 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698