OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 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_drm.h" | |
6 #include "third_party/libva/va/drm/va_drm.h" | |
7 #include "third_party/libva/va/va_drmcommon.h" | |
8 #include "third_party/libva/va/va_vpp.h" | |
9 #include "ui/gl/gl_bindings.h" | |
10 #include "ui/gl/gl_image.h" | |
11 #include "ui/gl/gl_image_egl.h" | |
12 #include "ui/gl/scoped_binders.h" | |
13 #include "ui/ozone/public/native_pixmap.h" | |
14 #include "ui/ozone/public/ozone_platform.h" | |
15 #include "ui/ozone/public/surface_factory_ozone.h" | |
16 | |
17 namespace content { | |
18 | |
19 #define LOG_VA_ERROR_AND_RETURN(input, err_msg) \ | |
20 do { \ | |
21 VAStatus va_status = input; \ | |
22 if (va_status != VA_STATUS_SUCCESS) { \ | |
23 DVLOG(1) << err_msg << " : " << vaErrorStr(va_status); \ | |
24 return false; \ | |
25 } \ | |
26 } while (0) | |
27 | |
28 class DrmPicture : public VaapiPictureProvider::Picture { | |
29 public: | |
30 DrmPicture(DrmVaapiPictureProvider* provider, | |
31 VADisplay va_display, | |
32 const base::Callback<bool(void)> make_context_current, | |
33 int32 picture_buffer_id, | |
34 uint32 texture_id, | |
35 const gfx::Size& size) | |
36 : Picture(picture_buffer_id, texture_id, size), | |
37 provider_(provider), | |
38 va_display_(va_display), | |
39 make_context_current_(make_context_current), | |
40 va_surface_(VA_INVALID_SURFACE) {} | |
41 | |
42 virtual ~DrmPicture() { | |
43 if (gl_image_ && make_context_current_.Run()) { | |
44 // ReleaseTexImage on a GLImageEGL does nothing, to deassociate | |
45 // the renderer's texture from the image, just set the storage | |
46 // of that texture to NULL | |
47 gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_2D, texture_id()); | |
48 glTexImage2D(GL_TEXTURE_2D, | |
49 0, | |
50 GL_RGBA, | |
51 size().width(), | |
52 size().height(), | |
53 0, | |
54 GL_RGBA, | |
55 GL_UNSIGNED_BYTE, | |
56 NULL); | |
57 | |
58 gl_image_->Destroy(true); | |
59 | |
60 CHECK_EQ(glGetError(), GL_NO_ERROR); | |
Pawel Osciak
2014/10/08 08:17:22
I think this is not critical enough to crash the p
llandwerlin-old
2014/10/08 09:31:18
Acknowledged.
| |
61 } | |
62 | |
63 if (va_surface_ != VA_INVALID_SURFACE) | |
64 vaDestroySurfaces(va_display_, &va_surface_, 1); | |
65 } | |
66 | |
67 bool Initialize() { | |
68 VASurfaceAttrib va_attribs[2]; | |
69 VASurfaceAttribExternalBuffers va_attrib_extbuf; | |
70 | |
71 ui::OzonePlatform* platform = ui::OzonePlatform::GetInstance(); | |
72 ui::SurfaceFactoryOzone* factory = platform->GetSurfaceFactoryOzone(); | |
73 | |
74 pixmap_ = | |
75 factory->CreateNativePixmap(size(), ui::SurfaceFactoryOzone::RGBA_8888); | |
Pawel Osciak
2014/10/08 08:17:22
Check for NULL?
llandwerlin-old
2014/10/08 09:31:18
Acknowledged.
| |
76 unsigned long buffer_fd = pixmap_->GetDmaBufFd(); | |
Pawel Osciak
2014/10/08 08:17:22
fd is an int... We should also check for -1.
llandwerlin-old
2014/10/08 09:31:18
Acknowledged.
| |
77 | |
78 va_attrib_extbuf.pixel_format = VA_FOURCC_BGRX; | |
79 va_attrib_extbuf.width = size().width(); | |
80 va_attrib_extbuf.height = size().height(); | |
81 va_attrib_extbuf.data_size = size().height() * pixmap_->GetStride(); | |
82 va_attrib_extbuf.num_planes = 1; | |
83 va_attrib_extbuf.pitches[0] = pixmap_->GetStride(); | |
84 va_attrib_extbuf.offsets[0] = 0; | |
85 va_attrib_extbuf.buffers = &buffer_fd; | |
86 va_attrib_extbuf.num_buffers = 1; | |
87 va_attrib_extbuf.flags = 0; | |
88 va_attrib_extbuf.private_data = NULL; | |
89 | |
90 va_attribs[0].type = VASurfaceAttribMemoryType; | |
91 va_attribs[0].flags = VA_SURFACE_ATTRIB_SETTABLE; | |
92 va_attribs[0].value.type = VAGenericValueTypeInteger; | |
93 va_attribs[0].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME; | |
94 | |
95 va_attribs[1].type = VASurfaceAttribExternalBufferDescriptor; | |
96 va_attribs[1].flags = VA_SURFACE_ATTRIB_SETTABLE; | |
97 va_attribs[1].value.type = VAGenericValueTypePointer; | |
98 va_attribs[1].value.value.p = &va_attrib_extbuf; | |
99 | |
100 LOG_VA_ERROR_AND_RETURN(vaCreateSurfaces(va_display_, | |
101 VA_RT_FORMAT_RGB32, | |
102 size().width(), | |
103 size().height(), | |
104 &va_surface_, | |
105 1, | |
106 va_attribs, | |
107 arraysize(va_attribs)), | |
108 "Couldn't create surface"); | |
109 | |
110 if (!make_context_current_.Run()) | |
111 return false; | |
112 | |
113 gl_image_ = new gfx::GLImageEGL(size()); | |
114 EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE}; | |
115 if (!gl_image_->Initialize( | |
116 EGL_NATIVE_PIXMAP_KHR, pixmap_->GetEGLClientBuffer(), attrs)) | |
117 return false; | |
118 | |
119 return true; | |
120 } | |
121 | |
122 virtual bool PutSurface(VASurfaceID va_surface_id) OVERRIDE { | |
123 if (!provider_->PutSurfaceIntoPicture(va_surface_id, va_surface_, size())) | |
124 return false; | |
125 | |
126 if (!make_context_current_.Run()) | |
127 return false; | |
128 | |
129 gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_2D, texture_id()); | |
130 return gl_image_->BindTexImage(GL_TEXTURE_2D); | |
131 } | |
132 | |
133 private: | |
134 DrmVaapiPictureProvider* provider_; | |
135 VADisplay va_display_; | |
136 base::Callback<bool(void)> make_context_current_; | |
137 VASurfaceID va_surface_; | |
138 scoped_refptr<ui::NativePixmap> pixmap_; | |
139 scoped_refptr<gfx::GLImageEGL> gl_image_; | |
140 }; | |
141 | |
142 DrmVaapiPictureProvider::DrmVaapiPictureProvider( | |
143 VADisplay va_display, | |
144 const base::Callback<bool(void)> make_context_current) | |
145 : make_context_current_(make_context_current), | |
146 va_display_(va_display), | |
147 vpp_config_(VA_INVALID_ID), | |
148 vpp_context_(VA_INVALID_ID), | |
149 vpp_buffer_(VA_INVALID_ID) { | |
150 } | |
151 | |
152 DrmVaapiPictureProvider::~DrmVaapiPictureProvider() { | |
153 DeinitializeVpp(); | |
154 } | |
155 | |
156 scoped_ptr<VaapiPictureProvider::Picture> | |
157 DrmVaapiPictureProvider::CreatePicture(int32 picture_buffer_id, | |
158 uint32 texture_id, | |
159 const gfx::Size& size) { | |
160 DrmPicture* drm_picture = new DrmPicture(this, | |
Pawel Osciak
2014/10/08 08:17:22
Could we create a scoped_ptr directly here?
scoped
llandwerlin-old
2014/10/08 09:31:18
The problem is that I can't access the Initialize
Pawel Osciak
2014/10/26 13:06:46
Could you pass fb_config_ to the constructor of TF
llandwerlin-old
2014/10/29 13:52:47
Acknowledged.
| |
161 va_display_, | |
162 make_context_current_, | |
163 picture_buffer_id, | |
164 texture_id, | |
165 size); | |
166 scoped_ptr<VaapiPictureProvider::Picture> picture(drm_picture); | |
Pawel Osciak
2014/10/08 08:17:22
Do we need the qualifier here if we are child of V
llandwerlin-old
2014/10/08 09:31:18
I'll check, thanks.
llandwerlin-old
2014/10/13 16:53:00
Yep, we do...
| |
167 | |
168 if (!drm_picture->Initialize()) | |
169 picture.reset(); | |
170 | |
171 return picture.Pass(); | |
172 } | |
173 | |
174 bool DrmVaapiPictureProvider::PutSurfaceIntoPicture( | |
175 VASurfaceID va_surface_id_src, | |
176 VASurfaceID va_surface_id_dest, | |
177 const gfx::Size& dest_size) { | |
178 VAProcPipelineParameterBuffer* pipeline_param; | |
179 VARectangle input_region, output_region; | |
180 | |
181 LOG_VA_ERROR_AND_RETURN( | |
182 vaMapBuffer(va_display_, vpp_buffer_, (void**)&pipeline_param), | |
183 "Couldn't map buffer"); | |
184 | |
185 memset(pipeline_param, 0, sizeof *pipeline_param); | |
186 | |
187 input_region.x = input_region.y = 0; | |
188 input_region.width = coded_picture_size_.width(); | |
189 input_region.height = coded_picture_size_.height(); | |
190 pipeline_param->surface_region = &input_region; | |
191 pipeline_param->surface = va_surface_id_src; | |
192 pipeline_param->surface_color_standard = VAProcColorStandardNone; | |
193 | |
194 output_region.x = output_region.y = 0; | |
195 output_region.width = dest_size.width(); | |
196 output_region.height = dest_size.height(); | |
197 pipeline_param->output_region = &output_region; | |
198 pipeline_param->output_background_color = 0xff000000; | |
199 pipeline_param->output_color_standard = VAProcColorStandardNone; | |
200 | |
201 LOG_VA_ERROR_AND_RETURN(vaUnmapBuffer(va_display_, vpp_buffer_), | |
202 "Couldn't unmap buffer"); | |
203 | |
204 LOG_VA_ERROR_AND_RETURN( | |
205 vaBeginPicture(va_display_, vpp_context_, va_surface_id_dest), | |
206 "Couldn't begin picture"); | |
207 | |
208 LOG_VA_ERROR_AND_RETURN( | |
209 vaRenderPicture(va_display_, vpp_context_, &vpp_buffer_, 1), | |
210 "Couldn't render picture"); | |
211 | |
212 LOG_VA_ERROR_AND_RETURN(vaEndPicture(va_display_, vpp_context_), | |
213 "Couldn't end picture"); | |
214 return true; | |
215 } | |
216 | |
217 bool DrmVaapiPictureProvider::SetCodedSurfacesSize(const gfx::Size& size) { | |
Pawel Osciak
2014/10/08 08:17:22
I realized, could we just do this on PutSurfaceInt
llandwerlin-old
2014/10/08 09:31:18
Acknowledged.
| |
218 DeinitializeVpp(); | |
219 return InitializeVpp(size); | |
220 } | |
221 | |
222 bool DrmVaapiPictureProvider::Initialize() { | |
223 return true; | |
224 } | |
225 | |
226 bool DrmVaapiPictureProvider::InitializeVpp(const gfx::Size& size) { | |
227 LOG_VA_ERROR_AND_RETURN(vaCreateConfig(va_display_, | |
228 VAProfileNone, | |
229 VAEntrypointVideoProc, | |
230 NULL, | |
231 0, | |
232 &vpp_config_), | |
233 "Couldn't create config"); | |
234 | |
235 LOG_VA_ERROR_AND_RETURN(vaCreateContext(va_display_, | |
236 vpp_config_, | |
237 size.width(), | |
238 size.height(), | |
239 0, | |
240 NULL, | |
241 0, | |
242 &vpp_context_), | |
243 "Couldn't create context"); | |
244 | |
245 LOG_VA_ERROR_AND_RETURN(vaCreateBuffer(va_display_, | |
246 vpp_context_, | |
247 VAProcPipelineParameterBufferType, | |
248 sizeof(VAProcPipelineParameterBuffer), | |
249 1, | |
250 NULL, | |
251 &vpp_buffer_), | |
252 "Couldn't create buffer"); | |
253 | |
254 coded_picture_size_ = size; | |
255 | |
256 return true; | |
257 } | |
258 | |
259 void DrmVaapiPictureProvider::DeinitializeVpp() { | |
260 if (vpp_buffer_ != VA_INVALID_ID) { | |
261 vaDestroyBuffer(va_display_, vpp_buffer_); | |
262 vpp_buffer_ = VA_INVALID_ID; | |
263 } | |
264 if (vpp_context_ != VA_INVALID_ID) { | |
265 vaDestroyContext(va_display_, vpp_context_); | |
266 vpp_context_ = VA_INVALID_ID; | |
267 } | |
268 if (vpp_config_ != VA_INVALID_ID) { | |
269 vaDestroyConfig(va_display_, vpp_config_); | |
270 vpp_config_ = VA_INVALID_ID; | |
271 } | |
272 } | |
273 | |
274 } // namespace | |
OLD | NEW |