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