Commit 2bd4e9c4 authored by Vikas Soni's avatar Vikas Soni Committed by Commit Bot

Add SharedImageRepresentationGLTextureAHardwareBuffer.

Implement SharedImageRepresentationGLTexture interface
for SharedImageBackingAHardwareBuffer.

Bug: 891060
Change-Id: I36429244c3643655124052392f983ee4713f60bb
Reviewed-on: https://chromium-review.googlesource.com/c/1294513
Commit-Queue: vikas soni <vikassoni@chromium.org>
Reviewed-by: default avatarAntoine Labour <piman@chromium.org>
Reviewed-by: default avatarEric Karl <ericrk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#602978}
parent 43d62bc1
......@@ -7,16 +7,41 @@
#include "base/android/android_hardware_buffer_compat.h"
#include "base/android/scoped_hardware_buffer_handle.h"
#include "base/logging.h"
#include "components/viz/common/resources/resource_format_utils.h"
#include "gpu/command_buffer/common/shared_image_usage.h"
#include "gpu/command_buffer/service/ahardwarebuffer_utils.h"
#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
#include "gpu/command_buffer/service/mailbox_manager.h"
#include "gpu/command_buffer/service/memory_tracking.h"
#include "gpu/command_buffer/service/shared_image_backing.h"
#include "gpu/config/gpu_driver_bug_workarounds.h"
#include "gpu/command_buffer/service/shared_image_representation.h"
#include "gpu/command_buffer/service/texture_manager.h"
#include "ui/gfx/color_space.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_gl_api_implementation.h"
#include "ui/gl/gl_image_ahardwarebuffer.h"
#include "ui/gl/gl_version_info.h"
namespace gpu {
// Representation of a SharedImageBackingAHardwareBuffer as a GL Texture.
class SharedImageRepresentationGLTextureAHardwareBuffer
: public SharedImageRepresentationGLTexture {
public:
SharedImageRepresentationGLTextureAHardwareBuffer(SharedImageManager* manager,
SharedImageBacking* backing,
gles2::Texture* texture)
: SharedImageRepresentationGLTexture(manager, backing),
texture_(texture) {}
gles2::Texture* GetTexture() override { return texture_; }
private:
gles2::Texture* texture_;
DISALLOW_COPY_AND_ASSIGN(SharedImageRepresentationGLTextureAHardwareBuffer);
};
// Implementation of SharedImageBacking that holds an AHardwareBuffer. This
// can be used to create a GL texture or a VK Image from the AHardwareBuffer
// backing.
......@@ -28,9 +53,11 @@ class SharedImageBackingAHardwareBuffer : public SharedImageBacking {
const gfx::Size& size,
const gfx::ColorSpace& color_space,
uint32_t usage,
base::android::ScopedHardwareBufferHandle handle)
base::android::ScopedHardwareBufferHandle handle,
MemoryTypeTracker* tracker)
: SharedImageBacking(mailbox, format, size, color_space, usage),
hardware_buffer_handle_(std::move(handle)) {
hardware_buffer_handle_(std::move(handle)),
memory_tracker_(tracker) {
DCHECK(hardware_buffer_handle_.is_valid());
}
......@@ -38,27 +65,122 @@ class SharedImageBackingAHardwareBuffer : public SharedImageBacking {
// Check to make sure buffer is explicitly destroyed using Destroy() api
// before this destructor is called.
DCHECK(!hardware_buffer_handle_.is_valid());
DCHECK(!texture_);
}
bool IsCleared() const override { return is_cleared_; }
bool IsCleared() const override {
if (texture_)
return texture_->IsLevelCleared(texture_->target(), 0);
return is_cleared_;
}
void SetCleared() override { is_cleared_ = true; }
void SetCleared() override {
if (texture_)
texture_->SetLevelCleared(texture_->target(), 0, true);
is_cleared_ = true;
}
bool ProduceLegacyMailbox(MailboxManager* mailbox_manager) override {
DCHECK(hardware_buffer_handle_.is_valid());
// Legacy mailbox is not supported.
return false;
if (!GenGLTexture())
return false;
DCHECK(texture_);
mailbox_manager->ProduceTexture(mailbox(), texture_);
return true;
}
void Destroy() override {
DCHECK(hardware_buffer_handle_.is_valid());
if (texture_) {
texture_->RemoveLightweightRef(have_context());
texture_ = nullptr;
}
hardware_buffer_handle_.reset();
}
protected:
std::unique_ptr<SharedImageRepresentationGLTexture> ProduceGLTexture(
SharedImageManager* manager) override {
// Use same texture for all the texture representations generated from same
// backing.
if (!GenGLTexture())
return nullptr;
DCHECK(texture_);
return std::make_unique<SharedImageRepresentationGLTextureAHardwareBuffer>(
manager, this, texture_);
}
private:
bool GenGLTexture() {
if (texture_)
return true;
DCHECK(hardware_buffer_handle_.is_valid());
DCHECK(usage() & SHARED_IMAGE_USAGE_GLES2);
// Target for AHB backed egl images.
GLenum target = GL_TEXTURE_EXTERNAL_OES;
GLenum get_target = GL_TEXTURE_BINDING_EXTERNAL_OES;
// Create a gles2 texture using the AhardwareBuffer.
gl::GLApi* api = gl::g_current_gl_context;
GLuint service_id = 0;
api->glGenTexturesFn(1, &service_id);
GLint old_texture_binding = 0;
api->glGetIntegervFn(get_target, &old_texture_binding);
api->glBindTextureFn(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(hardware_buffer_handle_.get(), false)) {
LOG(ERROR) << "Failed to create EGL image ";
api->glBindTextureFn(target, old_texture_binding);
api->glDeleteTexturesFn(1, &service_id);
return false;
}
if (!egl_image->BindTexImage(target)) {
LOG(ERROR) << "Failed to bind egl image";
api->glBindTextureFn(target, old_texture_binding);
api->glDeleteTexturesFn(1, &service_id);
return false;
}
// Create a gles2 Texture.
texture_ = new gles2::Texture(service_id);
texture_->SetLightweightRef(memory_tracker_);
texture_->SetTarget(target, 1);
texture_->sampler_state_.min_filter = GL_LINEAR;
texture_->sampler_state_.mag_filter = GL_LINEAR;
texture_->sampler_state_.wrap_t = GL_CLAMP_TO_EDGE;
texture_->sampler_state_.wrap_s = GL_CLAMP_TO_EDGE;
// If the backing is already cleared, no need to clear it again.
gfx::Rect cleared_rect;
if (is_cleared_)
cleared_rect = gfx::Rect(size());
GLenum gl_format = viz::GLDataFormat(format());
GLenum gl_type = viz::GLDataType(format());
texture_->SetLevelInfo(target, 0, egl_image->GetInternalFormat(),
size().width(), size().height(), 1, 0, gl_format,
gl_type, cleared_rect);
texture_->SetLevelImage(target, 0, egl_image.get(), gles2::Texture::BOUND);
texture_->SetImmutable(true);
api->glBindTextureFn(target, old_texture_binding);
return true;
}
base::android::ScopedHardwareBufferHandle hardware_buffer_handle_;
// This texture will be lazily initialised/created when ProduceGLTexture is
// called.
gles2::Texture* texture_ = nullptr;
// TODO(vikassoni): In future when we add begin/end write support, we will
// need to properly use this flag to pass the is_cleared_ information to
// the GL texture representation while begin write and back to this class from
......@@ -66,13 +188,66 @@ class SharedImageBackingAHardwareBuffer : public SharedImageBacking {
// will not know if SetCleared() arrives during begin write happening on GL
// texture representation.
bool is_cleared_ = false;
MemoryTypeTracker* memory_tracker_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(SharedImageBackingAHardwareBuffer);
};
SharedImageBackingFactoryAHardwareBuffer::
SharedImageBackingFactoryAHardwareBuffer(
const GpuDriverBugWorkarounds& workarounds) {
const GpuDriverBugWorkarounds& workarounds,
const GpuFeatureInfo& gpu_feature_info,
MemoryTracker* tracker)
: memory_tracker_(std::make_unique<MemoryTypeTracker>(tracker)) {
scoped_refptr<gles2::FeatureInfo> feature_info =
new gles2::FeatureInfo(workarounds, gpu_feature_info);
feature_info->Initialize(ContextType::CONTEXT_TYPE_OPENGLES2, false,
gles2::DisallowedFeatures());
const gles2::Validators* validators = feature_info->validators();
const bool is_egl_image_external_supported =
feature_info->feature_flags().oes_egl_image_external;
// Build the feature info for all the resource formats.
for (int i = 0; i <= viz::RESOURCE_FORMAT_MAX; ++i) {
auto format = static_cast<viz::ResourceFormat>(i);
FormatInfo& info = format_info_[i];
// If AHB does not support this format, we will not be able to create this
// backing.
if (!AHardwareBufferSupportedFormat(format))
continue;
info.ahb_supported = true;
info.ahb_format = AHardwareBufferFormat(format);
// Check if GL_TEXTURE_EXTERNAL_OES texture target is supported. This
// texture target is required to use AHB backed EGLImage as a texture.
if (!is_egl_image_external_supported)
continue;
// Check if AHB backed GL texture can be created using this format and
// gather GL related format info.
// TODO(vikassoni): Add vulkan related information in future.
GLuint internal_format = viz::GLInternalFormat(format);
GLenum gl_format = viz::GLDataFormat(format);
GLenum gl_type = viz::GLDataType(format);
// GLImageAHardwareBuffer currently supports internal format GL_RGBA only.
// TODO(vikassoni): Pass the AHBuffer format while GLImageAHardwareBuffer
// creation and based on that return the equivalent internal format as
// GL_RGBA or GL_RGB.
if (internal_format != GL_RGBA)
continue;
// Validate if GL format, type and internal format is supported.
if (validators->texture_internal_format.IsValid(internal_format) &&
validators->texture_format.IsValid(gl_format) &&
validators->pixel_type.IsValid(gl_type)) {
info.gl_supported = true;
info.gl_format = gl_format;
info.gl_type = gl_type;
info.internal_format = internal_format;
}
}
// TODO(vikassoni): We are using below GL api calls for now as Vulkan mode
// doesn't exist. Once we have vulkan support, we shouldn't query GL in this
// code until we are asked to make a GL representation (or allocate a backing
......@@ -103,18 +278,32 @@ SharedImageBackingFactoryAHardwareBuffer::CreateSharedImage(
uint32_t usage) {
DCHECK(base::AndroidHardwareBufferCompat::IsSupportAvailable());
const FormatInfo& format_info = format_info_[format];
// Check if the format is supported by AHardwareBuffer.
// TODO(vikassoni): We need to check if the equivalent GL texture format
// and VK image format support is available in the underlying hardware. Else
// we might not be able to use this AHB as a gl texture or VK Image.
// Additionally we also need to check usage flags to determine the format.
if (!AHardwareBufferSupportedFormat(format)) {
if (!format_info.ahb_supported) {
LOG(ERROR) << "viz::ResourceFormat " << format
<< "not supported by AHardwareBuffer";
<< " not supported by AHardwareBuffer";
return nullptr;
}
// Check for size restrictions.
// TODO(vikassoni): Also check for !gpu_preferences.enable_vulkan and maybe
// some other usage flags.
const bool use_gles2 = usage & SHARED_IMAGE_USAGE_GLES2;
// If usage flags indicated this backing can be used as a GL texture, then do
// below gl related checks.
if (use_gles2) {
// Check if the GL texture can be created from AHB with this format.
if (!format_info.gl_supported) {
LOG(ERROR)
<< "viz::ResourceFormat " << format
<< " can not be used to create a GL texture from AHardwareBuffer.";
return nullptr;
}
}
// Check if AHB can be created with the current size restrictions.
// TODO(vikassoni): Check for VK size restrictions for VK import, GL size
// restrictions for GL import OR both if this backing is needed to be used
// with both GL and VK.
......@@ -130,7 +319,7 @@ SharedImageBackingFactoryAHardwareBuffer::CreateSharedImage(
AHardwareBuffer_Desc hwb_desc;
hwb_desc.width = size.width();
hwb_desc.height = size.height();
hwb_desc.format = AHardwareBufferFormat(format);
hwb_desc.format = format_info.ahb_format;
// Set usage so that gpu can both read as a texture/write as a framebuffer
// attachment. TODO(vikassoni): Find out if we need to set some more usage
......@@ -155,8 +344,13 @@ SharedImageBackingFactoryAHardwareBuffer::CreateSharedImage(
auto backing = std::make_unique<SharedImageBackingAHardwareBuffer>(
mailbox, format, size, color_space, usage,
base::android::ScopedHardwareBufferHandle::Adopt(buffer));
base::android::ScopedHardwareBufferHandle::Adopt(buffer),
memory_tracker_.get());
return backing;
}
SharedImageBackingFactoryAHardwareBuffer::FormatInfo::FormatInfo() = default;
SharedImageBackingFactoryAHardwareBuffer::FormatInfo::~FormatInfo() = default;
} // namespace gpu
......@@ -9,6 +9,7 @@
#include "components/viz/common/resources/resource_format.h"
#include "gpu/command_buffer/service/shared_image_backing_factory.h"
#include "gpu/gpu_gles2_export.h"
#include "ui/gl/gl_bindings.h"
namespace gfx {
class Size;
......@@ -18,7 +19,10 @@ class ColorSpace;
namespace gpu {
class SharedImageBacking;
class GpuDriverBugWorkarounds;
struct GpuFeatureInfo;
struct Mailbox;
class MemoryTracker;
class MemoryTypeTracker;
// Implementation of SharedImageBackingFactory that produces AHardwareBuffer
// backed SharedImages. This is meant to be used on Android only.
......@@ -26,7 +30,9 @@ class GPU_GLES2_EXPORT SharedImageBackingFactoryAHardwareBuffer
: public SharedImageBackingFactory {
public:
SharedImageBackingFactoryAHardwareBuffer(
const GpuDriverBugWorkarounds& workarounds);
const GpuDriverBugWorkarounds& workarounds,
const GpuFeatureInfo& gpu_feature_info,
MemoryTracker* tracker);
~SharedImageBackingFactoryAHardwareBuffer() override;
// SharedImageBackingFactory implementation.
......@@ -38,8 +44,28 @@ class GPU_GLES2_EXPORT SharedImageBackingFactoryAHardwareBuffer
uint32_t usage) override;
private:
struct FormatInfo {
FormatInfo();
~FormatInfo();
// Whether this format is supported by AHardwareBuffer.
bool ahb_supported = false;
unsigned int ahb_format = 0;
// Whether this format can be used to create a GL texture from the AHB.
bool gl_supported = false;
// GL internal_format/format/type triplet.
GLuint internal_format = 0;
GLenum gl_format = 0;
GLenum gl_type = 0;
};
FormatInfo format_info_[viz::RESOURCE_FORMAT_MAX + 1];
// Used to limit the max size of AHardwareBuffer.
int32_t max_gl_texture_size_ = 0;
std::unique_ptr<MemoryTypeTracker> memory_tracker_;
DISALLOW_COPY_AND_ASSIGN(SharedImageBackingFactoryAHardwareBuffer);
};
......
......@@ -9,6 +9,9 @@
#include "gpu/command_buffer/common/shared_image_usage.h"
#include "gpu/command_buffer/service/mailbox_manager_impl.h"
#include "gpu/command_buffer/service/shared_image_backing.h"
#include "gpu/command_buffer/service/shared_image_manager.h"
#include "gpu/command_buffer/service/shared_image_representation.h"
#include "gpu/command_buffer/service/texture_manager.h"
#include "gpu/config/gpu_driver_bug_workarounds.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/color_space.h"
......@@ -39,7 +42,8 @@ class SharedImageBackingFactoryAHardwareBufferTest : public testing::Test {
GpuDriverBugWorkarounds workarounds;
workarounds.max_texture_size = INT_MAX - 1;
backing_factory_ =
std::make_unique<SharedImageBackingFactoryAHardwareBuffer>(workarounds);
std::make_unique<SharedImageBackingFactoryAHardwareBuffer>(
workarounds, GpuFeatureInfo(), nullptr);
}
protected:
......@@ -47,6 +51,7 @@ class SharedImageBackingFactoryAHardwareBufferTest : public testing::Test {
scoped_refptr<gl::GLContext> context_;
std::unique_ptr<SharedImageBackingFactoryAHardwareBuffer> backing_factory_;
gles2::MailboxManagerImpl mailbox_manager_;
SharedImageManager shared_image_manager_;
};
// Basic test to check creation and deletion of AHB backed shared image.
......@@ -63,13 +68,44 @@ TEST_F(SharedImageBackingFactoryAHardwareBufferTest, Basic) {
color_space, usage);
EXPECT_TRUE(backing);
// There is no Legacy mailbox support in AHardwareBuffer Implementation.
EXPECT_FALSE(backing->ProduceLegacyMailbox(&mailbox_manager_));
// Check clearing.
if (!backing->IsCleared()) {
backing->SetCleared();
EXPECT_TRUE(backing->IsCleared());
}
// First, validate via a legacy mailbox.
GLenum expected_target = GL_TEXTURE_EXTERNAL_OES;
EXPECT_TRUE(backing->ProduceLegacyMailbox(&mailbox_manager_));
TextureBase* texture_base = mailbox_manager_.ConsumeTexture(mailbox);
ASSERT_FALSE(texture_base);
// Destroy the backing resource.
backing->Destroy();
// Currently there is no support for passthrough texture on android and hence
// in AHB backing. So the TextureBase* should be pointing to a Texture object.
auto* texture = gles2::Texture::CheckedCast(texture_base);
ASSERT_TRUE(texture);
EXPECT_EQ(texture->target(), expected_target);
EXPECT_TRUE(texture->IsImmutable());
int width, height, depth;
bool has_level =
texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height, &depth);
EXPECT_TRUE(has_level);
EXPECT_EQ(width, size.width());
EXPECT_EQ(height, size.height());
// Next validate via a SharedImageRepresentationGLTexture.
EXPECT_TRUE(shared_image_manager_.Register(std::move(backing)));
auto gl_representation = shared_image_manager_.ProduceGLTexture(mailbox);
EXPECT_TRUE(gl_representation);
EXPECT_TRUE(gl_representation->GetTexture()->service_id());
EXPECT_EQ(expected_target, gl_representation->GetTexture()->target());
EXPECT_EQ(size, gl_representation->size());
EXPECT_EQ(format, gl_representation->format());
EXPECT_EQ(color_space, gl_representation->color_space());
EXPECT_EQ(usage, gl_representation->usage());
gl_representation.reset();
shared_image_manager_.Unregister(mailbox);
EXPECT_FALSE(mailbox_manager_.ConsumeTexture(mailbox));
}
// Test to check invalid format support.
......
......@@ -37,6 +37,7 @@ class DecoderContext;
class ServiceDiscardableManager;
class SharedImageBackingGLTexture;
class SharedImageBackingFactoryGLTexture;
class SharedImageBackingAHardwareBuffer;
class SharedImageRepresentationGLTexture;
namespace gles2 {
......@@ -354,6 +355,7 @@ class GPU_GLES2_EXPORT Texture final : public TextureBase {
friend class MailboxManagerTest;
friend class gpu::SharedImageBackingGLTexture;
friend class gpu::SharedImageBackingFactoryGLTexture;
friend class gpu::SharedImageBackingAHardwareBuffer;
friend class TextureDefinition;
friend class TextureManager;
friend class TextureRef;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment