blob: bec07037de1114901464946bee22a18d2032b4b0 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "gpu/command_buffer/service/ahardwarebuffer_utils.h"
#include <android/hardware_buffer.h>
#include "base/android/scoped_hardware_buffer_handle.h"
#include "base/check.h"
#include "base/notreached.h"
#include "components/viz/common/gpu/vulkan_context_provider.h"
#include "components/viz/common/resources/resource_format_utils.h"
#include "gpu/command_buffer/service/shared_context_state.h"
#include "gpu/command_buffer/service/texture_manager.h"
#include "gpu/vulkan/vulkan_image.h"
#include "ui/gfx/color_space.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gl/gl_gl_api_implementation.h"
#include "ui/gl/gl_image_ahardwarebuffer.h"
#include "ui/gl/scoped_binders.h"
namespace gpu {
namespace {
gles2::Texture* MakeGLTexture(
GLenum target,
GLuint service_id,
scoped_refptr<gl::GLImageAHardwareBuffer> egl_image,
const gfx::Size& size,
const gfx::Rect& cleared_rect) {
auto* texture = new gles2::Texture(service_id);
texture->SetLightweightRef();
texture->SetTarget(target, 1);
texture->set_min_filter(GL_LINEAR);
texture->set_mag_filter(GL_LINEAR);
texture->set_wrap_t(GL_CLAMP_TO_EDGE);
texture->set_wrap_s(GL_CLAMP_TO_EDGE);
texture->SetLevelInfo(target, 0, egl_image->GetInternalFormat(), size.width(),
size.height(), 1, 0, egl_image->GetDataFormat(),
egl_image->GetDataType(), cleared_rect);
texture->SetLevelImage(target, 0, egl_image.get(), gles2::Texture::BOUND);
texture->SetImmutable(true, false);
return texture;
}
scoped_refptr<gles2::TexturePassthrough> MakeGLTexturePassthrough(
GLenum target,
GLuint service_id,
scoped_refptr<gl::GLImageAHardwareBuffer> egl_image,
const size_t estimated_size) {
auto passthrough_texture =
base::MakeRefCounted<gles2::TexturePassthrough>(service_id, target);
passthrough_texture->SetEstimatedSize(estimated_size);
passthrough_texture->SetLevelImage(target, 0, egl_image.get());
passthrough_texture->set_is_bind_pending(false);
return passthrough_texture;
}
void 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) {
gl::GLApi* api = gl::g_current_gl_context;
GLuint service_id = 0;
api->glGenTexturesFn(1, &service_id);
gl::ScopedTextureBinder texture_binder(target, service_id);
api->glTexParameteriFn(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
api->glTexParameteriFn(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
api->glTexParameteriFn(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
api->glTexParameteriFn(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Create an egl image using AHardwareBuffer.
auto egl_image = base::MakeRefCounted<gl::GLImageAHardwareBuffer>(size);
if (!egl_image->Initialize(buffer, false)) {
LOG(ERROR) << "Failed to create EGL image";
api->glDeleteTexturesFn(1, &service_id);
return;
}
if (!egl_image->BindTexImage(target)) {
LOG(ERROR) << "Failed to bind egl image";
api->glDeleteTexturesFn(1, &service_id);
return;
}
egl_image->SetColorSpace(color_space);
if (passthrough_texture) {
*passthrough_texture = MakeGLTexturePassthrough(
target, service_id, std::move(egl_image), estimated_size);
} else {
*texture = MakeGLTexture(target, service_id, std::move(egl_image), size,
cleared_rect);
}
}
} // namespace
bool AHardwareBufferSupportedFormat(viz::ResourceFormat format) {
switch (format) {
case viz::RGBA_8888:
case viz::RGB_565:
case viz::BGR_565:
case viz::RGBA_F16:
case viz::RGBX_8888:
case viz::RGBA_1010102:
return true;
default:
return false;
}
}
unsigned int AHardwareBufferFormat(viz::ResourceFormat format) {
DCHECK(AHardwareBufferSupportedFormat(format));
switch (format) {
case viz::RGBA_8888:
return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
case viz::RGB_565:
return AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
case viz::BGR_565:
return AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
case viz::RGBA_F16:
return AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT;
case viz::RGBX_8888:
return AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM;
case viz::RGBA_1010102:
return AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM;
default:
NOTREACHED();
return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
}
}
gles2::Texture* GenGLTexture(AHardwareBuffer* buffer,
GLenum target,
const gfx::ColorSpace& color_space,
const gfx::Size& size,
const size_t estimated_size,
const gfx::Rect& cleared_rect) {
gles2::Texture* texture = nullptr;
GenGLTextureInternal(buffer, target, color_space, size, estimated_size,
cleared_rect, nullptr /* passthrough_texture */,
&texture);
return texture;
}
scoped_refptr<gles2::TexturePassthrough> GenGLTexturePassthrough(
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;
GenGLTextureInternal(buffer, target, color_space, size, estimated_size,
cleared_rect, &passthrough_texture,
nullptr /* texture */);
return passthrough_texture;
}
std::unique_ptr<VulkanImage> CreateVkImageFromAhbHandle(
base::android::ScopedHardwareBufferHandle ahb_handle,
SharedContextState* context_state,
const gfx::Size& size,
const viz::ResourceFormat& format,
uint32_t queue_family_index) {
DCHECK(context_state);
DCHECK(context_state->GrContextIsVulkan());
auto* device_queue = context_state->vk_context_provider()->GetDeviceQueue();
gfx::GpuMemoryBufferHandle gmb_handle(std::move(ahb_handle));
return VulkanImage::CreateFromGpuMemoryBufferHandle(
device_queue, std::move(gmb_handle), size, ToVkFormat(format),
/*usage=*/0, /*flags=*/0, /*image_tiling=*/VK_IMAGE_TILING_OPTIMAL,
/*queue_family_index=*/queue_family_index);
}
} // namespace gpu