1 // Copyright 2018 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 "gpu/command_buffer/service/ahardwarebuffer_utils.h"
6 
7 #include <android/hardware_buffer.h>
8 
9 #include "base/android/scoped_hardware_buffer_handle.h"
10 #include "base/check.h"
11 #include "base/notreached.h"
12 #include "components/viz/common/gpu/vulkan_context_provider.h"
13 #include "components/viz/common/resources/resource_format_utils.h"
14 #include "gpu/command_buffer/service/shared_context_state.h"
15 #include "gpu/command_buffer/service/texture_manager.h"
16 #include "gpu/vulkan/vulkan_image.h"
17 #include "ui/gfx/color_space.h"
18 #include "ui/gfx/geometry/size.h"
19 #include "ui/gl/gl_gl_api_implementation.h"
20 #include "ui/gl/gl_image_ahardwarebuffer.h"
21 #include "ui/gl/scoped_binders.h"
22 
23 namespace gpu {
24 namespace {
25 
MakeGLTexture(GLenum target,GLuint service_id,scoped_refptr<gl::GLImageAHardwareBuffer> egl_image,const gfx::Size & size,const gfx::Rect & cleared_rect)26 gles2::Texture* MakeGLTexture(
27     GLenum target,
28     GLuint service_id,
29     scoped_refptr<gl::GLImageAHardwareBuffer> egl_image,
30     const gfx::Size& size,
31     const gfx::Rect& cleared_rect) {
32   auto* texture = new gles2::Texture(service_id);
33   texture->SetLightweightRef();
34   texture->SetTarget(target, 1);
35   texture->set_min_filter(GL_LINEAR);
36   texture->set_mag_filter(GL_LINEAR);
37   texture->set_wrap_t(GL_CLAMP_TO_EDGE);
38   texture->set_wrap_s(GL_CLAMP_TO_EDGE);
39 
40   texture->SetLevelInfo(target, 0, egl_image->GetInternalFormat(), size.width(),
41                         size.height(), 1, 0, egl_image->GetDataFormat(),
42                         egl_image->GetDataType(), cleared_rect);
43   texture->SetLevelImage(target, 0, egl_image.get(), gles2::Texture::BOUND);
44   texture->SetImmutable(true, false);
45   return texture;
46 }
47 
MakeGLTexturePassthrough(GLenum target,GLuint service_id,scoped_refptr<gl::GLImageAHardwareBuffer> egl_image,const size_t estimated_size)48 scoped_refptr<gles2::TexturePassthrough> MakeGLTexturePassthrough(
49     GLenum target,
50     GLuint service_id,
51     scoped_refptr<gl::GLImageAHardwareBuffer> egl_image,
52     const size_t estimated_size) {
53   auto passthrough_texture =
54       base::MakeRefCounted<gles2::TexturePassthrough>(service_id, target);
55   passthrough_texture->SetEstimatedSize(estimated_size);
56   passthrough_texture->SetLevelImage(target, 0, egl_image.get());
57   passthrough_texture->set_is_bind_pending(false);
58   return passthrough_texture;
59 }
60 
GenGLTextureInternal(AHardwareBuffer * buffer,GLenum target,const gfx::ColorSpace & color_space,const gfx::Size & size,const size_t estimated_size,const gfx::Rect & cleared_rect,scoped_refptr<gles2::TexturePassthrough> * passthrough_texture,gles2::Texture ** texture)61 void GenGLTextureInternal(
62     AHardwareBuffer* buffer,
63     GLenum target,
64     const gfx::ColorSpace& color_space,
65     const gfx::Size& size,
66     const size_t estimated_size,
67     const gfx::Rect& cleared_rect,
68     scoped_refptr<gles2::TexturePassthrough>* passthrough_texture,
69     gles2::Texture** texture) {
70   gl::GLApi* api = gl::g_current_gl_context;
71   GLuint service_id = 0;
72   api->glGenTexturesFn(1, &service_id);
73   gl::ScopedTextureBinder texture_binder(target, service_id);
74 
75   api->glTexParameteriFn(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
76   api->glTexParameteriFn(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
77   api->glTexParameteriFn(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
78   api->glTexParameteriFn(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
79 
80   // Create an egl image using AHardwareBuffer.
81   auto egl_image = base::MakeRefCounted<gl::GLImageAHardwareBuffer>(size);
82   if (!egl_image->Initialize(buffer, false)) {
83     LOG(ERROR) << "Failed to create EGL image";
84     api->glDeleteTexturesFn(1, &service_id);
85     return;
86   }
87 
88   if (!egl_image->BindTexImage(target)) {
89     LOG(ERROR) << "Failed to bind egl image";
90     api->glDeleteTexturesFn(1, &service_id);
91     return;
92   }
93   egl_image->SetColorSpace(color_space);
94 
95   if (passthrough_texture) {
96     *passthrough_texture = MakeGLTexturePassthrough(
97         target, service_id, std::move(egl_image), estimated_size);
98   } else {
99     *texture = MakeGLTexture(target, service_id, std::move(egl_image), size,
100                              cleared_rect);
101   }
102 }
103 
104 }  // namespace
105 
AHardwareBufferSupportedFormat(viz::ResourceFormat format)106 bool AHardwareBufferSupportedFormat(viz::ResourceFormat format) {
107   switch (format) {
108     case viz::RGBA_8888:
109     case viz::RGB_565:
110     case viz::BGR_565:
111     case viz::RGBA_F16:
112     case viz::RGBX_8888:
113     case viz::RGBA_1010102:
114       return true;
115     default:
116       return false;
117   }
118 }
119 
AHardwareBufferFormat(viz::ResourceFormat format)120 unsigned int AHardwareBufferFormat(viz::ResourceFormat format) {
121   DCHECK(AHardwareBufferSupportedFormat(format));
122   switch (format) {
123     case viz::RGBA_8888:
124       return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
125     case viz::RGB_565:
126       return AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
127     case viz::BGR_565:
128       return AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
129     case viz::RGBA_F16:
130       return AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT;
131     case viz::RGBX_8888:
132       return AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM;
133     case viz::RGBA_1010102:
134       return AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM;
135     default:
136       NOTREACHED();
137       return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
138   }
139 }
140 
GenGLTexture(AHardwareBuffer * buffer,GLenum target,const gfx::ColorSpace & color_space,const gfx::Size & size,const size_t estimated_size,const gfx::Rect & cleared_rect)141 gles2::Texture* GenGLTexture(AHardwareBuffer* buffer,
142                              GLenum target,
143                              const gfx::ColorSpace& color_space,
144                              const gfx::Size& size,
145                              const size_t estimated_size,
146                              const gfx::Rect& cleared_rect) {
147   gles2::Texture* texture = nullptr;
148   GenGLTextureInternal(buffer, target, color_space, size, estimated_size,
149                        cleared_rect, nullptr /* passthrough_texture */,
150                        &texture);
151   return texture;
152 }
153 
GenGLTexturePassthrough(AHardwareBuffer * buffer,GLenum target,const gfx::ColorSpace & color_space,const gfx::Size & size,const size_t estimated_size,const gfx::Rect & cleared_rect)154 scoped_refptr<gles2::TexturePassthrough> GenGLTexturePassthrough(
155     AHardwareBuffer* buffer,
156     GLenum target,
157     const gfx::ColorSpace& color_space,
158     const gfx::Size& size,
159     const size_t estimated_size,
160     const gfx::Rect& cleared_rect) {
161   scoped_refptr<gles2::TexturePassthrough> passthrough_texture;
162   GenGLTextureInternal(buffer, target, color_space, size, estimated_size,
163                        cleared_rect, &passthrough_texture,
164                        nullptr /* texture */);
165   return passthrough_texture;
166 }
167 
CreateVkImageFromAhbHandle(base::android::ScopedHardwareBufferHandle ahb_handle,SharedContextState * context_state,const gfx::Size & size,const viz::ResourceFormat & format)168 std::unique_ptr<VulkanImage> CreateVkImageFromAhbHandle(
169     base::android::ScopedHardwareBufferHandle ahb_handle,
170     SharedContextState* context_state,
171     const gfx::Size& size,
172     const viz::ResourceFormat& format) {
173   DCHECK(context_state);
174   DCHECK(context_state->GrContextIsVulkan());
175 
176   auto* device_queue = context_state->vk_context_provider()->GetDeviceQueue();
177   gfx::GpuMemoryBufferHandle gmb_handle(std::move(ahb_handle));
178   return VulkanImage::CreateFromGpuMemoryBufferHandle(
179       device_queue, std::move(gmb_handle), size, ToVkFormat(format),
180       0 /* usage */);
181 }
182 
183 }  // namespace gpu
184