123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489 |
- // 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 <stdint.h>
- #include "base/barrier_closure.h"
- #include "base/logging.h"
- #include "base/numerics/checked_math.h"
- #include "base/numerics/safe_conversions.h"
- #include "base/synchronization/waitable_event.h"
- #include "base/system/sys_info.h"
- #include "base/task/thread_pool.h"
- #include "base/trace_event/trace_event.h"
- #include "build/build_config.h"
- #include "ui/gfx/buffer_format_util.h"
- #include "ui/gfx/gpu_fence.h"
- #include "ui/gl/buffer_format_utils.h"
- #include "ui/gl/gl_bindings.h"
- #include "ui/gl/gl_context.h"
- #include "ui/gl/gl_enums.h"
- #include "ui/gl/gl_surface.h"
- #include "ui/gl/gl_utils.h"
- #include "ui/gl/gl_version_info.h"
- #include "ui/gl/scoped_binders.h"
- #include "ui/gl/scoped_make_current.h"
- using gfx::BufferFormat;
- namespace gl {
- namespace {
- GLint DataRowLength(size_t stride, gfx::BufferFormat format) {
- switch (format) {
- case gfx::BufferFormat::RG_88:
- case gfx::BufferFormat::R_16:
- case gfx::BufferFormat::BGR_565:
- case gfx::BufferFormat::RGBA_4444:
- return base::checked_cast<GLint>(stride) / 2;
- case gfx::BufferFormat::RG_1616:
- case gfx::BufferFormat::RGBX_8888:
- case gfx::BufferFormat::RGBA_8888:
- case gfx::BufferFormat::BGRX_8888:
- case gfx::BufferFormat::BGRA_1010102:
- case gfx::BufferFormat::RGBA_1010102:
- case gfx::BufferFormat::BGRA_8888:
- return base::checked_cast<GLint>(stride) / 4;
- case gfx::BufferFormat::RGBA_F16:
- return base::checked_cast<GLint>(stride) / 8;
- case gfx::BufferFormat::R_8:
- return base::checked_cast<GLint>(stride);
- case gfx::BufferFormat::YVU_420:
- case gfx::BufferFormat::YUV_420_BIPLANAR:
- case gfx::BufferFormat::P010:
- NOTREACHED() << gfx::BufferFormatToString(format);
- return 0;
- }
- NOTREACHED();
- return 0;
- }
- template <typename F>
- std::vector<uint8_t> GLES2RGBData(const gfx::Size& size,
- size_t stride,
- const uint8_t* data,
- F const& data_to_rgb,
- GLenum* data_format,
- GLenum* data_type,
- GLint* data_row_length) {
- TRACE_EVENT2("gpu", "GLES2RGBData", "width", size.width(), "height",
- size.height());
- // Four-byte row alignment as specified by glPixelStorei with argument
- // GL_UNPACK_ALIGNMENT set to 4.
- size_t gles2_rgb_data_stride = (size.width() * 3 + 3) & ~3;
- std::vector<uint8_t> gles2_rgb_data(gles2_rgb_data_stride * size.height());
- for (int y = 0; y < size.height(); ++y) {
- for (int x = 0; x < size.width(); ++x) {
- data_to_rgb(&data[y * stride + x * 4],
- &gles2_rgb_data[y * gles2_rgb_data_stride + x * 3]);
- }
- }
- *data_format = GL_RGB;
- *data_type = GL_UNSIGNED_BYTE;
- *data_row_length = size.width();
- return gles2_rgb_data;
- }
- std::vector<uint8_t> GLES2RGB565Data(const gfx::Size& size,
- size_t stride,
- const uint8_t* data,
- GLenum* data_format,
- GLenum* data_type,
- GLint* data_row_length) {
- TRACE_EVENT2("gpu", "GLES2RGB565Data", "width", size.width(), "height",
- size.height());
- // Four-byte row alignment as specified by glPixelStorei with argument
- // GL_UNPACK_ALIGNMENT set to 4.
- size_t gles2_rgb_data_stride = (size.width() * 2 + 3) & ~3;
- std::vector<uint8_t> gles2_rgb_data(gles2_rgb_data_stride * size.height());
- for (int y = 0; y < size.height(); ++y) {
- for (int x = 0; x < size.width(); ++x) {
- const uint16_t* src =
- reinterpret_cast<const uint16_t*>(&data[y * stride + x * 2]);
- uint16_t* dst = reinterpret_cast<uint16_t*>(
- &gles2_rgb_data[y * gles2_rgb_data_stride + x * 2]);
- *dst = (((*src & 0x1f) >> 0) << 11) | (((*src & 0x7e0) >> 5) << 5) |
- (((*src & 0xf800) >> 11) << 5);
- }
- }
- *data_format = GL_RGB;
- *data_type = GL_UNSIGNED_SHORT_5_6_5;
- *data_row_length = size.width();
- return gles2_rgb_data;
- }
- absl::optional<std::vector<uint8_t>> GLES2Data(const gfx::Size& size,
- gfx::BufferFormat format,
- size_t stride,
- const uint8_t* data,
- GLenum* data_format,
- GLenum* data_type,
- GLint* data_row_length) {
- TRACE_EVENT2("gpu", "GLES2Data", "width", size.width(), "height",
- size.height());
- switch (format) {
- case gfx::BufferFormat::RGBX_8888:
- return absl::make_optional(GLES2RGBData(
- size, stride, data,
- [](const uint8_t* src, uint8_t* dst) {
- dst[0] = src[0];
- dst[1] = src[1];
- dst[2] = src[2];
- },
- data_format, data_type, data_row_length));
- case gfx::BufferFormat::BGR_565:
- return absl::make_optional(GLES2RGB565Data(
- size, stride, data, data_format, data_type, data_row_length));
- case gfx::BufferFormat::BGRX_8888:
- return absl::make_optional(GLES2RGBData(
- size, stride, data,
- [](const uint8_t* src, uint8_t* dst) {
- dst[0] = src[2];
- dst[1] = src[1];
- dst[2] = src[0];
- },
- data_format, data_type, data_row_length));
- case gfx::BufferFormat::RGBA_4444:
- case gfx::BufferFormat::RGBA_8888:
- case gfx::BufferFormat::BGRA_1010102:
- case gfx::BufferFormat::RGBA_1010102:
- case gfx::BufferFormat::BGRA_8888:
- case gfx::BufferFormat::RGBA_F16:
- case gfx::BufferFormat::R_8:
- case gfx::BufferFormat::R_16:
- case gfx::BufferFormat::RG_88:
- case gfx::BufferFormat::RG_1616: {
- size_t gles2_data_stride =
- RowSizeForBufferFormat(size.width(), format, 0);
- if (stride == gles2_data_stride ||
- g_current_gl_driver->ext.b_GL_EXT_unpack_subimage)
- return absl::nullopt; // No data conversion needed
- std::vector<uint8_t> gles2_data(gles2_data_stride * size.height());
- for (int y = 0; y < size.height(); ++y) {
- memcpy(&gles2_data[y * gles2_data_stride], &data[y * stride],
- gles2_data_stride);
- }
- *data_row_length = size.width();
- return absl::make_optional(gles2_data);
- }
- case gfx::BufferFormat::YVU_420:
- case gfx::BufferFormat::YUV_420_BIPLANAR:
- case gfx::BufferFormat::P010:
- NOTREACHED() << gfx::BufferFormatToString(format);
- return absl::nullopt;
- }
- NOTREACHED();
- return absl::nullopt;
- }
- void MemcpyTask(const void* src,
- void* dst,
- size_t bytes,
- size_t task_index,
- size_t n_tasks,
- base::RepeatingClosure* done) {
- auto checked_bytes = base::CheckedNumeric<size_t>(bytes);
- size_t start = (checked_bytes * task_index / n_tasks).ValueOrDie();
- size_t end = (checked_bytes * (task_index + 1) / n_tasks).ValueOrDie();
- DCHECK_LE(start, bytes);
- DCHECK_LE(end, bytes);
- memcpy(static_cast<char*>(dst) + start, static_cast<const char*>(src) + start,
- end - start);
- done->Run();
- }
- bool SupportsPBO(GLContext* context) {
- const GLVersionInfo* version = context->GetVersionInfo();
- return version->IsAtLeastGL(2, 1) || version->IsAtLeastGLES(3, 0) ||
- context->HasExtension("GL_ARB_pixel_buffer_object") ||
- context->HasExtension("GL_EXT_pixel_buffer_object") ||
- context->HasExtension("GL_NV_pixel_buffer_object");
- }
- bool SupportsMapBuffer(GLContext* context) {
- return context->GetVersionInfo()->IsAtLeastGL(2, 0) ||
- context->HasExtension("GL_OES_mapbuffer");
- }
- bool SupportsMapBufferRange(GLContext* context) {
- return context->GetVersionInfo()->IsAtLeastGLES(3, 0) ||
- context->HasExtension("GL_EXT_map_buffer_range");
- }
- } // namespace
- GLImageMemory::GLImageMemory(const gfx::Size& size)
- : size_(size),
- memory_(nullptr),
- format_(gfx::BufferFormat::RGBA_8888),
- stride_(0) {}
- GLImageMemory::~GLImageMemory() {
- if (buffer_ && original_context_ && original_surface_) {
- ui::ScopedMakeCurrent make_current(original_context_.get(),
- original_surface_.get());
- glDeleteBuffersARB(1, &buffer_);
- }
- }
- // static
- GLImageMemory* GLImageMemory::FromGLImage(GLImage* image) {
- if (!image || image->GetType() != Type::MEMORY)
- return nullptr;
- return static_cast<GLImageMemory*>(image);
- }
- bool GLImageMemory::Initialize(const unsigned char* memory,
- gfx::BufferFormat format,
- size_t stride) {
- if (!ValidFormat(format)) {
- LOG(ERROR) << "Invalid format: " << gfx::BufferFormatToString(format);
- return false;
- }
- if (stride < RowSizeForBufferFormat(size_.width(), format, 0) || stride & 3) {
- LOG(ERROR) << "Invalid stride: " << stride;
- return false;
- }
- DCHECK(memory);
- DCHECK(!memory_);
- memory_ = memory;
- format_ = format;
- stride_ = stride;
- bool tex_image_from_pbo_is_slow = false;
- #if BUILDFLAG(IS_WIN)
- tex_image_from_pbo_is_slow = true;
- #endif // BUILDFLAG(IS_WIN)
- GLContext* context = GLContext::GetCurrent();
- DCHECK(context);
- if (!tex_image_from_pbo_is_slow && SupportsPBO(context) &&
- (SupportsMapBuffer(context) || SupportsMapBufferRange(context))) {
- constexpr size_t kTaskBytes = 1024 * 1024;
- buffer_bytes_ = stride * size_.height();
- memcpy_tasks_ = std::min<size_t>(buffer_bytes_ / kTaskBytes,
- base::SysInfo::NumberOfProcessors());
- if (memcpy_tasks_ > 1) {
- glGenBuffersARB(1, &buffer_);
- ScopedBufferBinder binder(GL_PIXEL_UNPACK_BUFFER, buffer_);
- glBufferData(GL_PIXEL_UNPACK_BUFFER, buffer_bytes_, nullptr,
- GL_DYNAMIC_DRAW);
- original_context_ = context->AsWeakPtr();
- GLSurface* surface = GLSurface::GetCurrent();
- DCHECK(surface);
- original_surface_ = surface->AsWeakPtr();
- }
- }
- return true;
- }
- gfx::Size GLImageMemory::GetSize() {
- return size_;
- }
- unsigned GLImageMemory::GetInternalFormat() {
- return gl::BufferFormatToGLInternalFormat(format_);
- }
- unsigned GLImageMemory::GetDataFormat() {
- switch (format_) {
- case gfx::BufferFormat::RGBX_8888:
- case gfx::BufferFormat::RGBA_1010102:
- return GL_RGBA;
- case gfx::BufferFormat::BGRX_8888:
- case gfx::BufferFormat::BGRA_1010102:
- return GL_BGRA_EXT;
- default:
- break;
- }
- return GLImage::GetDataFormat();
- }
- unsigned GLImageMemory::GetDataType() {
- switch (format_) {
- case gfx::BufferFormat::BGR_565:
- return GL_UNSIGNED_SHORT_5_6_5_REV;
- default:
- break;
- }
- return gl::BufferFormatToGLDataType(format_);
- }
- GLImage::BindOrCopy GLImageMemory::ShouldBindOrCopy() {
- return COPY;
- }
- bool GLImageMemory::BindTexImage(unsigned target) {
- NOTREACHED();
- return false;
- }
- bool GLImageMemory::CopyTexImage(unsigned target) {
- TRACE_EVENT2("gpu", "GLImageMemory::CopyTexImage", "width", size_.width(),
- "height", size_.height());
- if (target == GL_TEXTURE_EXTERNAL_OES)
- return false;
- GLenum data_format = GetDataFormat();
- GLenum data_type = GetDataType();
- GLint data_row_length = DataRowLength(stride_, format_);
- absl::optional<std::vector<uint8_t>> gles2_data;
- GLContext* context = GLContext::GetCurrent();
- DCHECK(context);
- if (context->GetVersionInfo()->is_es) {
- gles2_data = GLES2Data(size_, format_, stride_, memory_, &data_format,
- &data_type, &data_row_length);
- }
- ScopedPixelStore scoped_unpack_row_length(
- GL_UNPACK_ROW_LENGTH,
- data_row_length == size_.width() ? 0 : data_row_length);
- ScopedPixelStore scoped_unpack_skip_pixels(GL_UNPACK_SKIP_PIXELS, 0);
- ScopedPixelStore scoped_unpack_skip_rows(GL_UNPACK_SKIP_ROWS, 0);
- ScopedPixelStore scoped_unpack_alignment(GL_UNPACK_ALIGNMENT, 4);
- const void* src;
- size_t size;
- if (gles2_data) {
- src = gles2_data->data();
- size = gles2_data->size();
- } else {
- src = memory_;
- size = buffer_bytes_;
- }
- bool uploaded = false;
- if (buffer_ && original_context_.get() == context) {
- glTexImage2D(target, 0, GetInternalFormat(), size_.width(), size_.height(),
- 0, data_format, data_type, nullptr);
- ScopedBufferBinder binder(GL_PIXEL_UNPACK_BUFFER, buffer_);
- void* dst = nullptr;
- if (SupportsMapBuffer(context)) {
- dst = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
- } else {
- DCHECK(SupportsMapBufferRange(context));
- dst = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, size, GL_MAP_WRITE_BIT);
- }
- if (dst) {
- base::WaitableEvent event;
- base::RepeatingClosure barrier = base::BarrierClosure(
- memcpy_tasks_, base::BindOnce(&base::WaitableEvent::Signal,
- base::Unretained(&event)));
- for (int i = 1; i < memcpy_tasks_; ++i) {
- base::ThreadPool::PostTask(
- FROM_HERE, base::BindOnce(&MemcpyTask, src, dst, size, i,
- memcpy_tasks_, &barrier));
- }
- MemcpyTask(src, dst, size, 0, memcpy_tasks_, &barrier);
- event.Wait();
- glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
- glTexSubImage2D(target, 0, 0, 0, size_.width(), size_.height(),
- data_format, data_type, 0);
- uploaded = true;
- } else {
- glDeleteBuffersARB(1, &buffer_);
- buffer_ = 0;
- }
- }
- if (!uploaded) {
- glTexImage2D(target, 0, GetInternalFormat(), size_.width(), size_.height(),
- 0, data_format, data_type, src);
- }
- return true;
- }
- bool GLImageMemory::CopyTexSubImage(unsigned target,
- const gfx::Point& offset,
- const gfx::Rect& rect) {
- TRACE_EVENT2("gpu", "GLImageMemory::CopyTexSubImage", "width", rect.width(),
- "height", rect.height());
- // GL_TEXTURE_EXTERNAL_OES is not a supported target.
- if (target == GL_TEXTURE_EXTERNAL_OES)
- return false;
- // Sub width is not supported.
- if (rect.width() != size_.width())
- return false;
- const uint8_t* data = memory_ + rect.y() * stride_;
- GLenum data_format = GetDataFormat();
- GLenum data_type = GetDataType();
- GLint data_row_length = DataRowLength(stride_, format_);
- absl::optional<std::vector<uint8_t>> gles2_data;
- if (GLContext::GetCurrent()->GetVersionInfo()->is_es) {
- gles2_data = GLES2Data(rect.size(), format_, stride_, data, &data_format,
- &data_type, &data_row_length);
- }
- ScopedPixelStore scoped_unpack_row_length(
- GL_UNPACK_ROW_LENGTH,
- data_row_length == rect.width() ? 0 : data_row_length);
- ScopedPixelStore scoped_unpack_skip_pixels(GL_UNPACK_SKIP_PIXELS, 0);
- ScopedPixelStore scoped_unpack_skip_rows(GL_UNPACK_SKIP_ROWS, 0);
- ScopedPixelStore scoped_unpack_alignment(GL_UNPACK_ALIGNMENT, 4);
- glTexSubImage2D(target, 0, offset.x(), offset.y(), rect.width(),
- rect.height(), data_format, data_type,
- gles2_data ? gles2_data->data() : data);
- return true;
- }
- GLImageMemory::Type GLImageMemory::GetType() const {
- return Type::MEMORY;
- }
- // static
- bool GLImageMemory::ValidFormat(gfx::BufferFormat format) {
- switch (format) {
- case gfx::BufferFormat::R_8:
- case gfx::BufferFormat::R_16:
- case gfx::BufferFormat::RG_88:
- case gfx::BufferFormat::RG_1616:
- case gfx::BufferFormat::BGR_565:
- case gfx::BufferFormat::RGBA_4444:
- case gfx::BufferFormat::RGBX_8888:
- case gfx::BufferFormat::RGBA_8888:
- case gfx::BufferFormat::BGRX_8888:
- case gfx::BufferFormat::BGRA_1010102:
- case gfx::BufferFormat::RGBA_1010102:
- case gfx::BufferFormat::BGRA_8888:
- case gfx::BufferFormat::RGBA_F16:
- return true;
- case gfx::BufferFormat::YVU_420:
- case gfx::BufferFormat::YUV_420_BIPLANAR:
- case gfx::BufferFormat::P010:
- return false;
- }
- NOTREACHED();
- return false;
- }
- } // namespace gl
|