// Copyright 2023 The Chromium Authors
// 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/abstract_texture_android.h"
#include "gpu/command_buffer/service/texture_manager.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_surface.h"
#include "ui/gl/scoped_binders.h"
#include "ui/gl/scoped_make_current.h"
namespace gpu {
namespace {
GLuint CreateTextureWithLinearFilter() {
const auto target = GL_TEXTURE_EXTERNAL_OES;
GLuint service_id = 0;
auto* api = gl::g_current_gl_context;
api->glGenTexturesFn(1, &service_id);
gl::ScopedTextureBinder 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);
return service_id;
}
} // namespace
std::unique_ptr<AbstractTextureAndroid>
AbstractTextureAndroid::CreateForValidating(gfx::Size size) {
GLuint service_id = CreateTextureWithLinearFilter();
auto* texture = gpu::gles2::CreateGLES2TextureWithLightRef(
service_id, GL_TEXTURE_EXTERNAL_OES);
gfx::Rect cleared_rect;
texture->SetLevelInfo(GL_TEXTURE_EXTERNAL_OES, 0, GL_RGBA, size.width(),
size.height(), 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
cleared_rect);
texture->SetImmutable(true, false);
return std::make_unique<AbstractTextureAndroid>(texture);
}
std::unique_ptr<AbstractTextureAndroid>
AbstractTextureAndroid::CreateForPassthrough(gfx::Size size) {
GLuint service_id = CreateTextureWithLinearFilter();
auto texture = base::MakeRefCounted<gles2::TexturePassthrough>(
service_id, GL_TEXTURE_EXTERNAL_OES);
return std::make_unique<AbstractTextureAndroid>(std::move(texture), size);
}
std::unique_ptr<AbstractTextureAndroid>
AbstractTextureAndroid::CreateForTesting(GLuint texture_id) {
auto texture = std::make_unique<gpu::TextureBase>(texture_id);
return std::make_unique<AbstractTextureAndroid>(std::move(texture));
}
AbstractTextureAndroid::AbstractTextureAndroid(
std::unique_ptr<gpu::TextureBase> texture)
: texture_for_testing_(std::move(texture)) {}
AbstractTextureAndroid::AbstractTextureAndroid(gles2::Texture* texture)
: texture_(texture), api_(gl::g_current_gl_context) {}
AbstractTextureAndroid::AbstractTextureAndroid(
scoped_refptr<gles2::TexturePassthrough> texture,
const gfx::Size& size)
: texture_passthrough_(std::move(texture)),
texture_passthrough_size_(size),
api_(gl::g_current_gl_context) {
DCHECK(texture_passthrough_ &&
texture_passthrough_->target() == GL_TEXTURE_EXTERNAL_OES);
}
AbstractTextureAndroid::~AbstractTextureAndroid() {
// If context is not lost, then the texture should be destroyed on same
// context it was create on.
if ((texture_ || texture_passthrough_) && have_context_) {
DCHECK_EQ(api_, gl::g_current_gl_context);
}
if (texture_) {
texture_.ExtractAsDangling()->RemoveLightweightRef(have_context_);
}
}
void AbstractTextureAndroid::NotifyOnContextLost() {
if (texture_passthrough_) {
texture_passthrough_->MarkContextLost();
}
have_context_ = false;
}
void AbstractTextureAndroid::BindToServiceId(GLuint service_id) {
if (texture_) {
texture_->BindToServiceId(service_id);
texture_->SetLevelCleared(texture_->target(), /*level=*/0, true);
} else if (texture_passthrough_) {
texture_passthrough_->BindToServiceId(service_id);
if (gl::g_current_gl_driver->ext.b_GL_ANGLE_texture_external_update) {
// Notify the texture that its size has changed.
unsigned int target = texture_passthrough_->target();
GLint prev_texture = 0;
glGetIntegerv(gles2::GetTextureBindingQuery(target), &prev_texture);
glBindTexture(target, texture_passthrough_->service_id());
glTexImage2DExternalANGLE(
target, /*level=*/0, /*internalformat=*/GL_RGBA,
texture_passthrough_size_.width(), texture_passthrough_size_.height(),
/*border=*/0, /*format=*/GL_RGBA, /*type=*/GL_UNSIGNED_BYTE);
glBindTexture(target, prev_texture);
}
}
}
TextureBase* AbstractTextureAndroid::GetTextureBase() const {
if (texture_) {
return texture_;
}
if (texture_passthrough_) {
return texture_passthrough_.get();
}
if (texture_for_testing_) {
return texture_for_testing_.get();
}
return nullptr;
}
} // namespace gpu