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 "media/gpu/vaapi/vaapi_picture_native_pixmap_ozone.h"
6 
7 #include "media/gpu/vaapi/va_surface.h"
8 #include "media/gpu/vaapi/vaapi_wrapper.h"
9 #include "ui/gfx/gpu_memory_buffer.h"
10 #include "ui/gfx/native_pixmap.h"
11 #include "ui/gl/gl_bindings.h"
12 #include "ui/gl/gl_image_native_pixmap.h"
13 #include "ui/gl/scoped_binders.h"
14 #include "ui/ozone/public/ozone_platform.h"
15 #include "ui/ozone/public/surface_factory_ozone.h"
16 
17 namespace media {
18 
VaapiPictureNativePixmapOzone(scoped_refptr<VaapiWrapper> vaapi_wrapper,const MakeGLContextCurrentCallback & make_context_current_cb,const BindGLImageCallback & bind_image_cb,int32_t picture_buffer_id,const gfx::Size & size,const gfx::Size & visible_size,uint32_t texture_id,uint32_t client_texture_id,uint32_t texture_target)19 VaapiPictureNativePixmapOzone::VaapiPictureNativePixmapOzone(
20     scoped_refptr<VaapiWrapper> vaapi_wrapper,
21     const MakeGLContextCurrentCallback& make_context_current_cb,
22     const BindGLImageCallback& bind_image_cb,
23     int32_t picture_buffer_id,
24     const gfx::Size& size,
25     const gfx::Size& visible_size,
26     uint32_t texture_id,
27     uint32_t client_texture_id,
28     uint32_t texture_target)
29     : VaapiPictureNativePixmap(std::move(vaapi_wrapper),
30                                make_context_current_cb,
31                                bind_image_cb,
32                                picture_buffer_id,
33                                size,
34                                visible_size,
35                                texture_id,
36                                client_texture_id,
37                                texture_target) {
38   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
39   // Either |texture_id| and |client_texture_id| are both zero, or not.
40   DCHECK((texture_id == 0 && client_texture_id == 0) ||
41          (texture_id != 0 && client_texture_id != 0));
42 }
43 
~VaapiPictureNativePixmapOzone()44 VaapiPictureNativePixmapOzone::~VaapiPictureNativePixmapOzone() {
45   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
46   if (gl_image_ && make_context_current_cb_.Run()) {
47     gl_image_->ReleaseTexImage(texture_target_);
48     DCHECK_EQ(glGetError(), static_cast<GLenum>(GL_NO_ERROR));
49   }
50 }
51 
Initialize(scoped_refptr<gfx::NativePixmap> pixmap)52 bool VaapiPictureNativePixmapOzone::Initialize(
53     scoped_refptr<gfx::NativePixmap> pixmap) {
54   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
55   DCHECK(pixmap);
56   DCHECK(pixmap->AreDmaBufFdsValid());
57   // Create a |va_surface_| from dmabuf fds (pixmap->GetDmaBufFd)
58   va_surface_ = vaapi_wrapper_->CreateVASurfaceForPixmap(pixmap);
59   if (!va_surface_) {
60     LOG(ERROR) << "Failed creating VASurface for NativePixmap";
61     return false;
62   }
63 
64   // ARC++ has no texture ids.
65   if (texture_id_ == 0 && client_texture_id_ == 0)
66     return true;
67 
68   // Import dmabuf fds into the output gl texture through EGLImage.
69   if (make_context_current_cb_ && !make_context_current_cb_.Run())
70     return false;
71 
72   gl::ScopedTextureBinder texture_binder(texture_target_, texture_id_);
73 
74   const gfx::BufferFormat format = pixmap->GetBufferFormat();
75 
76   auto image =
77       base::MakeRefCounted<gl::GLImageNativePixmap>(visible_size_, format);
78   if (!image->Initialize(std::move(pixmap))) {
79     LOG(ERROR) << "Failed to create GLImage";
80     return false;
81   }
82 
83   gl_image_ = image;
84   if (!gl_image_->BindTexImage(texture_target_)) {
85     LOG(ERROR) << "Failed to bind texture to GLImage";
86     return false;
87   }
88 
89   if (bind_image_cb_ &&
90       !bind_image_cb_.Run(client_texture_id_, texture_target_, gl_image_,
91                           true /* can_bind_to_sampler */)) {
92     LOG(ERROR) << "Failed to bind client_texture_id";
93     return false;
94   }
95 
96   return true;
97 }
98 
Allocate(gfx::BufferFormat format)99 bool VaapiPictureNativePixmapOzone::Allocate(gfx::BufferFormat format) {
100   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
101 
102   ui::OzonePlatform* platform = ui::OzonePlatform::GetInstance();
103   ui::SurfaceFactoryOzone* factory = platform->GetSurfaceFactoryOzone();
104   auto pixmap = factory->CreateNativePixmap(
105       gfx::kNullAcceleratedWidget, VK_NULL_HANDLE, size_, format,
106       gfx::BufferUsage::SCANOUT_VDA_WRITE, /*framebuffer_size=*/visible_size_);
107   if (!pixmap) {
108     LOG(ERROR) << "Failed allocating a pixmap";
109     return false;
110   }
111 
112   return Initialize(std::move(pixmap));
113 }
114 
ImportGpuMemoryBufferHandle(gfx::BufferFormat format,gfx::GpuMemoryBufferHandle gpu_memory_buffer_handle)115 bool VaapiPictureNativePixmapOzone::ImportGpuMemoryBufferHandle(
116     gfx::BufferFormat format,
117     gfx::GpuMemoryBufferHandle gpu_memory_buffer_handle) {
118   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
119 
120   const auto& plane = gpu_memory_buffer_handle.native_pixmap_handle.planes[0];
121   if (size_.width() > static_cast<int>(plane.stride) ||
122       size_.GetArea() > static_cast<int>(plane.size)) {
123     DLOG(ERROR) << "GpuMemoryBufferHandle (stride=" << plane.stride
124                 << ", size=" << plane.size
125                 << "is smaller than size_=" << size_.ToString();
126     return false;
127   }
128 
129   ui::OzonePlatform* platform = ui::OzonePlatform::GetInstance();
130   ui::SurfaceFactoryOzone* factory = platform->GetSurfaceFactoryOzone();
131   // CreateNativePixmapFromHandle() will take ownership of the handle.
132   auto pixmap = factory->CreateNativePixmapFromHandle(
133       gfx::kNullAcceleratedWidget, size_, format,
134       std::move(gpu_memory_buffer_handle.native_pixmap_handle));
135 
136   if (!pixmap) {
137     LOG(ERROR) << "Failed creating a pixmap from a native handle";
138     return false;
139   }
140 
141   return Initialize(std::move(pixmap));
142 }
143 
144 }  // namespace media
145