1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136

gpu / command_buffer / service / shared_image / gl_texture_passthrough_fallback_image_representation.cc [blame]

// 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/shared_image/gl_texture_passthrough_fallback_image_representation.h"

#include "base/bits.h"
#include "components/viz/common/resources/shared_image_format_utils.h"
#include "gpu/command_buffer/service/shared_image/shared_image_format_service_utils.h"
#include "gpu/command_buffer/service/shared_image/shared_image_gl_utils.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/progress_reporter.h"
#include "ui/gl/scoped_restore_texture.h"

namespace gpu {
namespace {
GLFormatDesc GetGLFormatDesc(viz::SharedImageFormat format,
                             int plane_index,
                             const GLFormatCaps& gl_format_caps) {
  GLFormatDesc gl_format_desc;
  if (format.is_multi_plane()) {
    gl_format_desc = gl_format_caps.ToGLFormatDesc(format, plane_index);
  } else {
    // For legacy multiplanar formats, `format` is already plane format (eg.
    // RED, RG), so we pass plane_index=0.
    gl_format_desc = gl_format_caps.ToGLFormatDesc(format, /*plane_index=*/0);
  }
  return gl_format_desc;
}

scoped_refptr<gles2::TexturePassthrough> CreateGLTexture(
    const GLFormatDesc& format_desc,
    const gfx::Size& size,
    gl::ProgressReporter* progress_reporter) {
  gl::GLApi* const api = gl::g_current_gl_context;
  const GLenum target = format_desc.target;
  gl::ScopedRestoreTexture scoped_restore(api, target);

  GLuint service_id = 0;
  api->glGenTexturesFn(1, &service_id);
  api->glBindTextureFn(target, service_id);

  // These need to be set for the texture to be considered mipmap complete.
  api->glTexParameteriFn(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  api->glTexParameteriFn(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

  // These are not strictly required but guard against some checks if NPOT
  // texture support is disabled.
  api->glTexParameteriFn(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  api->glTexParameteriFn(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

  gl::ScopedProgressReporter scoped_progress_reporter(progress_reporter);

  // Use glTexImage2D instead of glTexStorage2D so that we can later use
  // glTexSubImage2D in GLTextureHolder::UploadFromMemory.
  api->glTexImage2DFn(target, 0, format_desc.image_internal_format,
                      size.width(), size.height(), 0, format_desc.data_format,
                      format_desc.data_type, nullptr);

  return base::MakeRefCounted<gles2::TexturePassthrough>(service_id, target);
}
}  // namespace

GLTexturePassthroughFallbackImageRepresentation::
    GLTexturePassthroughFallbackImageRepresentation(
        SharedImageManager* manager,
        SharedImageBacking* backing,
        MemoryTypeTracker* tracker,
        gl::ProgressReporter* progress_reporter,
        const GLFormatCaps& gl_format_caps)
    : GLTexturePassthroughImageRepresentation(manager, backing, tracker) {
  for (int plane = 0; plane < format().NumberOfPlanes(); plane++) {
    const gfx::Size plane_size = format().GetPlaneSize(plane, size());
    const SkColorType plane_ct = viz::ToClosestSkColorType(format(), plane);
    const SkImageInfo plane_info = SkImageInfo::Make(
        plane_size.width(), plane_size.height(), plane_ct, kPremul_SkAlphaType);
    static constexpr size_t kDefaultGLAlignment = 4;
    plane_bitmaps_.emplace_back().allocPixels(
        plane_info,
        base::bits::AlignUp(plane_info.minRowBytes(), kDefaultGLAlignment));
    plane_pixmaps_.push_back(plane_bitmaps_.back().pixmap());

    const GLFormatDesc format_desc =
        GetGLFormatDesc(format(), plane, gl_format_caps);
    plane_textures_
        .emplace_back(viz::SkColorTypeToSinglePlaneSharedImageFormat(plane_ct),
                      plane_size, /*is_passthrough=*/true, progress_reporter)
        .InitializeWithTexture(
            format_desc,
            CreateGLTexture(format_desc, plane_size, progress_reporter));
  }
}

GLTexturePassthroughFallbackImageRepresentation::
    ~GLTexturePassthroughFallbackImageRepresentation() = default;

const scoped_refptr<gles2::TexturePassthrough>&
GLTexturePassthroughFallbackImageRepresentation::GetTexturePassthrough(
    int plane_index) {
  CHECK_GE(plane_index, 0);
  CHECK_LT(static_cast<size_t>(plane_index), plane_textures_.size());
  return plane_textures_[plane_index].passthrough_texture();
}

bool GLTexturePassthroughFallbackImageRepresentation::BeginAccess(GLenum mode) {
  // Only readback from backing if already cleared.
  if (IsCleared()) {
    if (!backing()->ReadbackToMemory(plane_pixmaps_)) {
      LOG(ERROR) << "Backing ReadbackToMemory failed";
      return false;
    }

    for (int plane = 0; plane < format().NumberOfPlanes(); plane++) {
      if (!plane_textures_[plane].UploadFromMemory(plane_pixmaps_[plane])) {
        LOG(ERROR) << "GL UploadFromMemory failed";
        return false;
      }
    }
  }
  return true;
}

void GLTexturePassthroughFallbackImageRepresentation::EndAccess() {
  for (int plane = 0; plane < format().NumberOfPlanes(); plane++) {
    if (!plane_textures_[plane].ReadbackToMemory(plane_pixmaps_[plane])) {
      LOG(ERROR) << "GL ReadbackToMemory failed";
      return;
    }
  }

  if (!backing()->UploadFromMemory(plane_pixmaps_)) {
    LOG(ERROR) << "Backing UploadFromMemory failed";
  }
}

}  // namespace gpu