blob: d680b332685510104096fa1b57033d556603d855 [file] [log] [blame]
// Copyright 2020 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/shared_image_representation_gl_ozone.h"
#include <memory>
#include "base/memory/ptr_util.h"
#include "base/memory/scoped_refptr.h"
#include "components/viz/common/resources/resource_format.h"
#include "components/viz/common/resources/resource_format_utils.h"
#include "gpu/command_buffer/service/memory_tracking.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 "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/gfx/native_pixmap.h"
#include "ui/gl/buffer_format_utils.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_fence.h"
#include "ui/gl/gl_gl_api_implementation.h"
#include "ui/gl/gl_image_native_pixmap.h"
#include "ui/gl/gl_image_shared_memory.h"
#include "ui/gl/gl_version_info.h"
#include "ui/gl/scoped_binders.h"
#include "ui/gl/trace_util.h"
namespace gpu {
bool SharedImageRepresentationGLOzoneShared::BeginAccess(
SharedImageBackingOzone* ozone_backing) {
std::vector<gfx::GpuFenceHandle> fences;
ozone_backing->BeginAccess(&fences);
if (ozone_backing->NeedsSynchronization()) {
// ChromeOS VMs don't support gpu fences, so there is no good way to
// synchronize with GL.
if (gl::GLFence::IsGpuFenceSupported()) {
for (auto& fence : fences) {
gfx::GpuFence gpu_fence = gfx::GpuFence(std::move(fence));
std::unique_ptr<gl::GLFence> gl_fence =
gl::GLFence::CreateFromGpuFence(gpu_fence);
gl_fence->ServerWait();
}
}
}
// We must call VaapiWrapper::SyncSurface() to ensure all VA-API work is done
// prior to using the buffer in a graphics API.
return ozone_backing->VaSync();
}
void SharedImageRepresentationGLOzoneShared::EndAccess(
GLenum mode,
SharedImageBackingOzone* ozone_backing) {
gfx::GpuFenceHandle fence;
if (ozone_backing->NeedsSynchronization()) {
// ChromeOS VMs don't support gpu fences, so there is no good way to
// synchronize with GL.
if (gl::GLFence::IsGpuFenceSupported()) {
auto gl_fence = gl::GLFence::CreateForGpuFence();
DCHECK(gl_fence);
fence = gl_fence->GetGpuFence()->GetGpuFenceHandle().Clone();
}
}
bool readonly = mode != GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM;
ozone_backing->EndAccess(readonly, std::move(fence));
}
scoped_refptr<gl::GLImageNativePixmap>
SharedImageRepresentationGLOzoneShared::CreateGLImage(
scoped_refptr<gfx::NativePixmap> pixmap,
gfx::BufferFormat buffer_format) {
scoped_refptr<gl::GLImageNativePixmap> image =
base::MakeRefCounted<gl::GLImageNativePixmap>(pixmap->GetBufferSize(),
buffer_format);
if (!image->Initialize(std::move(pixmap))) {
LOG(ERROR) << "Unable to initialize GL image from pixmap";
return nullptr;
}
return image;
}
absl::optional<GLuint> SharedImageRepresentationGLOzoneShared::SetupTexture(
scoped_refptr<gl::GLImageNativePixmap> image,
GLenum target) {
gl::GLApi* api = gl::g_current_gl_context;
DCHECK(api);
GLuint gl_texture_service_id;
api->glGenTexturesFn(1, &gl_texture_service_id);
gl::ScopedTextureBinder binder(target, gl_texture_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);
if (!image->BindTexImage(target)) {
LOG(ERROR) << "Unable to bind GL image to target = " << target;
api->glDeleteTexturesFn(1, &gl_texture_service_id);
return absl::nullopt;
}
return gl_texture_service_id;
}
// static
std::unique_ptr<SharedImageRepresentationGLTextureOzone>
SharedImageRepresentationGLTextureOzone::Create(
SharedImageManager* manager,
SharedImageBacking* backing,
MemoryTypeTracker* tracker,
scoped_refptr<gfx::NativePixmap> pixmap,
viz::ResourceFormat format) {
gfx::BufferFormat buffer_format = viz::BufferFormat(format);
GLenum target = !NativeBufferNeedsPlatformSpecificTextureTarget(buffer_format)
? GL_TEXTURE_2D
: gpu::GetPlatformSpecificTextureTarget();
auto image = SharedImageRepresentationGLOzoneShared::CreateGLImage(
pixmap, buffer_format);
if (!image) {
return nullptr;
}
auto gl_texture_service_id =
SharedImageRepresentationGLOzoneShared::SetupTexture(image, target);
if (!gl_texture_service_id.has_value()) {
return nullptr;
}
gles2::Texture* texture = new gles2::Texture(*gl_texture_service_id);
texture->SetLightweightRef();
texture->SetTarget(target, 1 /*max_levels=*/);
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);
GLuint internal_format = viz::TextureStorageFormat(format);
GLenum gl_format = viz::GLDataFormat(format);
GLenum gl_type = viz::GLDataType(format);
texture->SetLevelInfo(target, 0, internal_format,
pixmap->GetBufferSize().width(),
pixmap->GetBufferSize().height(), 1, 0, gl_format,
gl_type, backing->ClearedRect());
texture->SetLevelImage(target, 0, image.get(), gles2::Texture::BOUND);
texture->SetImmutable(true, true);
return base::WrapUnique<SharedImageRepresentationGLTextureOzone>(
new SharedImageRepresentationGLTextureOzone(manager, backing, tracker,
texture));
}
SharedImageRepresentationGLTextureOzone::
SharedImageRepresentationGLTextureOzone(SharedImageManager* manager,
SharedImageBacking* backing,
MemoryTypeTracker* tracker,
gles2::Texture* texture)
: SharedImageRepresentationGLTexture(manager, backing, tracker),
texture_(texture) {}
SharedImageRepresentationGLTextureOzone::
~SharedImageRepresentationGLTextureOzone() {
texture_->RemoveLightweightRef(has_context());
}
gles2::Texture* SharedImageRepresentationGLTextureOzone::GetTexture() {
return texture_;
}
bool SharedImageRepresentationGLTextureOzone::BeginAccess(GLenum mode) {
DCHECK(!current_access_mode_);
current_access_mode_ = mode;
return SharedImageRepresentationGLOzoneShared::BeginAccess(ozone_backing());
}
void SharedImageRepresentationGLTextureOzone::EndAccess() {
SharedImageRepresentationGLOzoneShared::EndAccess(current_access_mode_,
ozone_backing());
current_access_mode_ = 0;
}
// static
std::unique_ptr<SharedImageRepresentationGLTexturePassthroughOzone>
SharedImageRepresentationGLTexturePassthroughOzone::Create(
SharedImageManager* manager,
SharedImageBacking* backing,
MemoryTypeTracker* tracker,
scoped_refptr<gfx::NativePixmap> pixmap,
viz::ResourceFormat format) {
gfx::BufferFormat buffer_format = viz::BufferFormat(format);
GLenum target = !NativeBufferNeedsPlatformSpecificTextureTarget(buffer_format)
? GL_TEXTURE_2D
: gpu::GetPlatformSpecificTextureTarget();
auto image = SharedImageRepresentationGLOzoneShared::CreateGLImage(
pixmap, buffer_format);
if (!image) {
return nullptr;
}
auto gl_texture_service_id =
SharedImageRepresentationGLOzoneShared::SetupTexture(image, target);
if (!gl_texture_service_id.has_value()) {
return nullptr;
}
GLuint internal_format = viz::TextureStorageFormat(format);
GLenum gl_format = viz::GLDataFormat(format);
GLenum gl_type = viz::GLDataType(format);
scoped_refptr<gles2::TexturePassthrough> texture_passthrough =
base::MakeRefCounted<gpu::gles2::TexturePassthrough>(
*gl_texture_service_id, target, internal_format,
backing->size().width(), backing->size().height(),
/*depth=*/1, /*border=*/0, gl_format, gl_type);
return base::WrapUnique<SharedImageRepresentationGLTexturePassthroughOzone>(
new SharedImageRepresentationGLTexturePassthroughOzone(
manager, backing, tracker, texture_passthrough));
}
SharedImageRepresentationGLTexturePassthroughOzone::
SharedImageRepresentationGLTexturePassthroughOzone(
SharedImageManager* manager,
SharedImageBacking* backing,
MemoryTypeTracker* tracker,
scoped_refptr<gles2::TexturePassthrough> texture_passthrough)
: SharedImageRepresentationGLTexturePassthrough(manager, backing, tracker),
texture_passthrough_(texture_passthrough) {}
SharedImageRepresentationGLTexturePassthroughOzone::
~SharedImageRepresentationGLTexturePassthroughOzone() = default;
const scoped_refptr<gles2::TexturePassthrough>&
SharedImageRepresentationGLTexturePassthroughOzone::GetTexturePassthrough() {
return texture_passthrough_;
}
bool SharedImageRepresentationGLTexturePassthroughOzone::BeginAccess(
GLenum mode) {
DCHECK(!current_access_mode_);
current_access_mode_ = mode;
return SharedImageRepresentationGLOzoneShared::BeginAccess(ozone_backing());
}
void SharedImageRepresentationGLTexturePassthroughOzone::EndAccess() {
SharedImageRepresentationGLOzoneShared::EndAccess(current_access_mode_,
ozone_backing());
current_access_mode_ = 0;
}
} // namespace gpu