mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
382 lines
11 KiB
C++
382 lines
11 KiB
C++
// Copyright 2014 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 "ui/gl/gl_image_memory.h"
|
|
|
|
#include "base/logging.h"
|
|
#include "base/trace_event/trace_event.h"
|
|
#include "ui/gl/gl_bindings.h"
|
|
#include "ui/gl/gl_surface_egl.h"
|
|
#include "ui/gl/scoped_binders.h"
|
|
|
|
namespace gfx {
|
|
namespace {
|
|
|
|
bool ValidInternalFormat(unsigned internalformat) {
|
|
switch (internalformat) {
|
|
case GL_RGBA:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool ValidFormat(gfx::GpuMemoryBuffer::Format format) {
|
|
switch (format) {
|
|
case gfx::GpuMemoryBuffer::ATC:
|
|
case gfx::GpuMemoryBuffer::ATCIA:
|
|
case gfx::GpuMemoryBuffer::DXT1:
|
|
case gfx::GpuMemoryBuffer::DXT5:
|
|
case gfx::GpuMemoryBuffer::ETC1:
|
|
case gfx::GpuMemoryBuffer::RGBA_8888:
|
|
case gfx::GpuMemoryBuffer::BGRA_8888:
|
|
return true;
|
|
case gfx::GpuMemoryBuffer::RGBX_8888:
|
|
return false;
|
|
}
|
|
|
|
NOTREACHED();
|
|
return false;
|
|
}
|
|
|
|
bool IsCompressedFormat(gfx::GpuMemoryBuffer::Format format) {
|
|
switch (format) {
|
|
case gfx::GpuMemoryBuffer::ATC:
|
|
case gfx::GpuMemoryBuffer::ATCIA:
|
|
case gfx::GpuMemoryBuffer::DXT1:
|
|
case gfx::GpuMemoryBuffer::DXT5:
|
|
case gfx::GpuMemoryBuffer::ETC1:
|
|
return true;
|
|
case gfx::GpuMemoryBuffer::RGBA_8888:
|
|
case gfx::GpuMemoryBuffer::BGRA_8888:
|
|
case gfx::GpuMemoryBuffer::RGBX_8888:
|
|
return false;
|
|
}
|
|
|
|
NOTREACHED();
|
|
return false;
|
|
}
|
|
|
|
GLenum TextureFormat(gfx::GpuMemoryBuffer::Format format) {
|
|
switch (format) {
|
|
case gfx::GpuMemoryBuffer::ATC:
|
|
return GL_ATC_RGB_AMD;
|
|
case gfx::GpuMemoryBuffer::ATCIA:
|
|
return GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD;
|
|
case gfx::GpuMemoryBuffer::DXT1:
|
|
return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
|
|
case gfx::GpuMemoryBuffer::DXT5:
|
|
return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
|
case gfx::GpuMemoryBuffer::ETC1:
|
|
return GL_ETC1_RGB8_OES;
|
|
case gfx::GpuMemoryBuffer::RGBA_8888:
|
|
return GL_RGBA;
|
|
case gfx::GpuMemoryBuffer::BGRA_8888:
|
|
return GL_BGRA_EXT;
|
|
case gfx::GpuMemoryBuffer::RGBX_8888:
|
|
NOTREACHED();
|
|
return 0;
|
|
}
|
|
|
|
NOTREACHED();
|
|
return 0;
|
|
}
|
|
|
|
GLenum DataFormat(gfx::GpuMemoryBuffer::Format format) {
|
|
return TextureFormat(format);
|
|
}
|
|
|
|
GLenum DataType(gfx::GpuMemoryBuffer::Format format) {
|
|
switch (format) {
|
|
case gfx::GpuMemoryBuffer::RGBA_8888:
|
|
case gfx::GpuMemoryBuffer::BGRA_8888:
|
|
return GL_UNSIGNED_BYTE;
|
|
case gfx::GpuMemoryBuffer::ATC:
|
|
case gfx::GpuMemoryBuffer::ATCIA:
|
|
case gfx::GpuMemoryBuffer::DXT1:
|
|
case gfx::GpuMemoryBuffer::DXT5:
|
|
case gfx::GpuMemoryBuffer::ETC1:
|
|
case gfx::GpuMemoryBuffer::RGBX_8888:
|
|
NOTREACHED();
|
|
return 0;
|
|
}
|
|
|
|
NOTREACHED();
|
|
return 0;
|
|
}
|
|
|
|
GLsizei SizeInBytes(const gfx::Size& size,
|
|
gfx::GpuMemoryBuffer::Format format) {
|
|
size_t stride_in_bytes = 0;
|
|
bool valid_stride = GLImageMemory::StrideInBytes(
|
|
size.width(), format, &stride_in_bytes);
|
|
DCHECK(valid_stride);
|
|
return static_cast<GLsizei>(stride_in_bytes * size.height());
|
|
}
|
|
|
|
} // namespace
|
|
|
|
GLImageMemory::GLImageMemory(const gfx::Size& size, unsigned internalformat)
|
|
: size_(size),
|
|
internalformat_(internalformat),
|
|
memory_(NULL),
|
|
format_(gfx::GpuMemoryBuffer::RGBA_8888),
|
|
in_use_(false),
|
|
target_(0),
|
|
need_do_bind_tex_image_(false),
|
|
egl_texture_id_(0u),
|
|
egl_image_(EGL_NO_IMAGE_KHR) {
|
|
}
|
|
|
|
GLImageMemory::~GLImageMemory() {
|
|
DCHECK_EQ(EGL_NO_IMAGE_KHR, egl_image_);
|
|
DCHECK_EQ(0u, egl_texture_id_);
|
|
}
|
|
|
|
// static
|
|
bool GLImageMemory::StrideInBytes(size_t width,
|
|
gfx::GpuMemoryBuffer::Format format,
|
|
size_t* stride_in_bytes) {
|
|
base::CheckedNumeric<size_t> s = width;
|
|
switch (format) {
|
|
case gfx::GpuMemoryBuffer::ATCIA:
|
|
case gfx::GpuMemoryBuffer::DXT5:
|
|
*stride_in_bytes = width;
|
|
return true;
|
|
case gfx::GpuMemoryBuffer::ATC:
|
|
case gfx::GpuMemoryBuffer::DXT1:
|
|
case gfx::GpuMemoryBuffer::ETC1:
|
|
DCHECK_EQ(width % 2, 0U);
|
|
s /= 2;
|
|
if (!s.IsValid())
|
|
return false;
|
|
|
|
*stride_in_bytes = s.ValueOrDie();
|
|
return true;
|
|
case gfx::GpuMemoryBuffer::RGBA_8888:
|
|
case gfx::GpuMemoryBuffer::BGRA_8888:
|
|
s *= 4;
|
|
if (!s.IsValid())
|
|
return false;
|
|
|
|
*stride_in_bytes = s.ValueOrDie();
|
|
return true;
|
|
case gfx::GpuMemoryBuffer::RGBX_8888:
|
|
NOTREACHED();
|
|
return false;
|
|
}
|
|
|
|
NOTREACHED();
|
|
return false;
|
|
}
|
|
|
|
bool GLImageMemory::Initialize(const unsigned char* memory,
|
|
gfx::GpuMemoryBuffer::Format format) {
|
|
if (!ValidInternalFormat(internalformat_)) {
|
|
LOG(ERROR) << "Invalid internalformat: " << internalformat_;
|
|
return false;
|
|
}
|
|
|
|
if (!ValidFormat(format)) {
|
|
LOG(ERROR) << "Invalid format: " << format;
|
|
return false;
|
|
}
|
|
|
|
DCHECK(memory);
|
|
DCHECK(!memory_);
|
|
DCHECK_IMPLIES(IsCompressedFormat(format), size_.width() % 4 == 0);
|
|
DCHECK_IMPLIES(IsCompressedFormat(format), size_.height() % 4 == 0);
|
|
memory_ = memory;
|
|
format_ = format;
|
|
return true;
|
|
}
|
|
|
|
void GLImageMemory::Destroy(bool have_context) {
|
|
if (egl_image_ != EGL_NO_IMAGE_KHR) {
|
|
eglDestroyImageKHR(GLSurfaceEGL::GetHardwareDisplay(), egl_image_);
|
|
egl_image_ = EGL_NO_IMAGE_KHR;
|
|
}
|
|
|
|
if (egl_texture_id_) {
|
|
if (have_context)
|
|
glDeleteTextures(1, &egl_texture_id_);
|
|
egl_texture_id_ = 0u;
|
|
}
|
|
memory_ = NULL;
|
|
}
|
|
|
|
gfx::Size GLImageMemory::GetSize() {
|
|
return size_;
|
|
}
|
|
|
|
bool GLImageMemory::BindTexImage(unsigned target) {
|
|
if (target_ && target_ != target) {
|
|
LOG(ERROR) << "GLImage can only be bound to one target";
|
|
return false;
|
|
}
|
|
target_ = target;
|
|
|
|
// Defer DoBindTexImage if not currently in use.
|
|
if (!in_use_) {
|
|
need_do_bind_tex_image_ = true;
|
|
return true;
|
|
}
|
|
|
|
DoBindTexImage(target);
|
|
return true;
|
|
}
|
|
|
|
bool GLImageMemory::CopyTexImage(unsigned target) {
|
|
TRACE_EVENT0("gpu", "GLImageMemory::CopyTexImage");
|
|
|
|
// GL_TEXTURE_EXTERNAL_OES is not a supported CopyTexImage target.
|
|
if (target == GL_TEXTURE_EXTERNAL_OES)
|
|
return false;
|
|
|
|
DCHECK(memory_);
|
|
if (IsCompressedFormat(format_)) {
|
|
glCompressedTexSubImage2D(target,
|
|
0, // level
|
|
0, // x-offset
|
|
0, // y-offset
|
|
size_.width(), size_.height(),
|
|
DataFormat(format_), SizeInBytes(size_, format_),
|
|
memory_);
|
|
} else {
|
|
glTexSubImage2D(target, 0, // level
|
|
0, // x
|
|
0, // y
|
|
size_.width(), size_.height(), DataFormat(format_),
|
|
DataType(format_), memory_);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void GLImageMemory::WillUseTexImage() {
|
|
DCHECK(!in_use_);
|
|
in_use_ = true;
|
|
|
|
if (!need_do_bind_tex_image_)
|
|
return;
|
|
|
|
DCHECK(target_);
|
|
DoBindTexImage(target_);
|
|
}
|
|
|
|
void GLImageMemory::DidUseTexImage() {
|
|
DCHECK(in_use_);
|
|
in_use_ = false;
|
|
}
|
|
|
|
bool GLImageMemory::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
|
|
int z_order,
|
|
OverlayTransform transform,
|
|
const Rect& bounds_rect,
|
|
const RectF& crop_rect) {
|
|
return false;
|
|
}
|
|
|
|
void GLImageMemory::DoBindTexImage(unsigned target) {
|
|
TRACE_EVENT0("gpu", "GLImageMemory::DoBindTexImage");
|
|
|
|
DCHECK(need_do_bind_tex_image_);
|
|
need_do_bind_tex_image_ = false;
|
|
|
|
DCHECK(memory_);
|
|
if (target == GL_TEXTURE_EXTERNAL_OES) {
|
|
if (egl_image_ == EGL_NO_IMAGE_KHR) {
|
|
DCHECK_EQ(0u, egl_texture_id_);
|
|
glGenTextures(1, &egl_texture_id_);
|
|
|
|
{
|
|
ScopedTextureBinder texture_binder(GL_TEXTURE_2D, egl_texture_id_);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
if (IsCompressedFormat(format_)) {
|
|
glCompressedTexImage2D(GL_TEXTURE_2D,
|
|
0, // mip level
|
|
TextureFormat(format_), size_.width(),
|
|
size_.height(),
|
|
0, // border
|
|
SizeInBytes(size_, format_), memory_);
|
|
} else {
|
|
glTexImage2D(GL_TEXTURE_2D,
|
|
0, // mip level
|
|
TextureFormat(format_),
|
|
size_.width(),
|
|
size_.height(),
|
|
0, // border
|
|
DataFormat(format_),
|
|
DataType(format_),
|
|
memory_);
|
|
}
|
|
}
|
|
|
|
EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
|
|
// Need to pass current EGL rendering context to eglCreateImageKHR for
|
|
// target type EGL_GL_TEXTURE_2D_KHR.
|
|
egl_image_ =
|
|
eglCreateImageKHR(GLSurfaceEGL::GetHardwareDisplay(),
|
|
eglGetCurrentContext(),
|
|
EGL_GL_TEXTURE_2D_KHR,
|
|
reinterpret_cast<EGLClientBuffer>(egl_texture_id_),
|
|
attrs);
|
|
DCHECK_NE(EGL_NO_IMAGE_KHR, egl_image_)
|
|
<< "Error creating EGLImage: " << eglGetError();
|
|
} else {
|
|
ScopedTextureBinder texture_binder(GL_TEXTURE_2D, egl_texture_id_);
|
|
|
|
if (IsCompressedFormat(format_)) {
|
|
glCompressedTexSubImage2D(GL_TEXTURE_2D,
|
|
0, // mip level
|
|
0, // x-offset
|
|
0, // y-offset
|
|
size_.width(), size_.height(),
|
|
DataFormat(format_),
|
|
SizeInBytes(size_, format_),
|
|
memory_);
|
|
} else {
|
|
glTexSubImage2D(GL_TEXTURE_2D,
|
|
0, // mip level
|
|
0, // x-offset
|
|
0, // y-offset
|
|
size_.width(),
|
|
size_.height(),
|
|
DataFormat(format_),
|
|
DataType(format_),
|
|
memory_);
|
|
}
|
|
}
|
|
|
|
glEGLImageTargetTexture2DOES(target, egl_image_);
|
|
DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
|
|
return;
|
|
}
|
|
|
|
DCHECK_NE(static_cast<GLenum>(GL_TEXTURE_EXTERNAL_OES), target);
|
|
if (IsCompressedFormat(format_)) {
|
|
glCompressedTexImage2D(target,
|
|
0, // mip level
|
|
TextureFormat(format_), size_.width(),
|
|
size_.height(),
|
|
0, // border
|
|
SizeInBytes(size_, format_), memory_);
|
|
} else {
|
|
glTexImage2D(target,
|
|
0, // mip level
|
|
TextureFormat(format_),
|
|
size_.width(),
|
|
size_.height(),
|
|
0, // border
|
|
DataFormat(format_),
|
|
DataType(format_),
|
|
memory_);
|
|
}
|
|
}
|
|
|
|
} // namespace gfx
|