Flutter Impeller
sampler_gles.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
6 
7 #include <algorithm>
8 
14 
15 namespace impeller {
16 
17 SamplerGLES::SamplerGLES(const SamplerDescriptor& desc) : Sampler(desc) {}
18 
19 SamplerGLES::~SamplerGLES() = default;
20 
21 static GLint ToParam(MinMagFilter minmag_filter) {
22  switch (minmag_filter) {
23  case MinMagFilter::kNearest:
24  return GL_NEAREST;
25  case MinMagFilter::kLinear:
26  return GL_LINEAR;
27  }
28  FML_UNREACHABLE();
29 }
30 
31 static GLint ToParam(MinMagFilter minmag_filter, MipFilter mip_filter) {
32  switch (mip_filter) {
33  case MipFilter::kBase:
34  return ToParam(minmag_filter);
35  case MipFilter::kNearest:
36  switch (minmag_filter) {
37  case MinMagFilter::kNearest:
38  return GL_NEAREST_MIPMAP_NEAREST;
39  case MinMagFilter::kLinear:
40  return GL_LINEAR_MIPMAP_NEAREST;
41  }
42  case MipFilter::kLinear:
43  switch (minmag_filter) {
44  case MinMagFilter::kNearest:
45  return GL_NEAREST_MIPMAP_LINEAR;
46  case MinMagFilter::kLinear:
47  return GL_LINEAR_MIPMAP_LINEAR;
48  }
49  }
50  FML_UNREACHABLE();
51 }
52 
54  bool supports_decal_sampler_address_mode) {
55  switch (mode) {
56  case SamplerAddressMode::kClampToEdge:
57  return GL_CLAMP_TO_EDGE;
58  case SamplerAddressMode::kRepeat:
59  return GL_REPEAT;
60  case SamplerAddressMode::kMirror:
61  return GL_MIRRORED_REPEAT;
62  case SamplerAddressMode::kDecal:
63  if (supports_decal_sampler_address_mode) {
65  } else {
66  return GL_CLAMP_TO_EDGE;
67  }
68  }
69  FML_UNREACHABLE();
70 }
71 
72 bool SamplerGLES::ConfigureBoundTexture(const TextureGLES& texture,
73  const ProcTableGLES& gl) const {
74  auto target = ToTextureTarget(texture.GetTextureDescriptor().type);
75 
76  if (!target.has_value()) {
77  return false;
78  }
79  const SamplerDescriptor& desc = GetDescriptor();
80 
81  GLint mag_filter = ToParam(desc.mag_filter);
82 
83  // If the texture doesn't have mipmaps, we can't use mip filtering.
84  GLint min_filter;
85  if (texture.GetTextureDescriptor().mip_count > 1) {
86  min_filter = ToParam(desc.min_filter, desc.mip_filter);
87  } else {
88  min_filter = ToParam(desc.min_filter);
89  }
90 
91  gl.TexParameteri(*target, GL_TEXTURE_MIN_FILTER, min_filter);
92  gl.TexParameteri(*target, GL_TEXTURE_MAG_FILTER, mag_filter);
93 
94  // Bound the sampled mip range to the levels the texture declares. GLES leaves
95  // GL_TEXTURE_MAX_LEVEL at its default of 1000, so a texture sampled with a
96  // mipmap filter reads as black unless every level down to 1x1 is defined.
97  // Metal and Vulkan allocate exactly mip_count levels, and clamping here gives
98  // the same behavior for a partial, manually uploaded mip chain. The parameter
99  // is unavailable on ES 2.0 without GL_APPLE_texture_max_level, and external
100  // textures have no mip levels, so it is skipped in those cases.
101  if (*target != GL_TEXTURE_EXTERNAL_OES &&
102  gl.GetCapabilities()->SupportsTextureMaxLevel()) {
103  const GLint max_level =
104  static_cast<GLint>(texture.GetTextureDescriptor().mip_count) - 1;
105  gl.TexParameteri(*target, GL_TEXTURE_MAX_LEVEL, max_level);
106  }
107 
108  const auto supports_decal_mode =
109  gl.GetCapabilities()->SupportsDecalSamplerAddressMode();
110 
111  const auto wrap_s =
112  ToAddressMode(desc.width_address_mode, supports_decal_mode);
113  const auto wrap_t =
114  ToAddressMode(desc.height_address_mode, supports_decal_mode);
115 
116  gl.TexParameteri(*target, GL_TEXTURE_WRAP_S, wrap_s);
117  gl.TexParameteri(*target, GL_TEXTURE_WRAP_T, wrap_t);
118 
119  if (wrap_s == IMPELLER_GL_CLAMP_TO_BORDER ||
120  wrap_t == IMPELLER_GL_CLAMP_TO_BORDER) {
121  // Transparent black.
122  const GLfloat border_color[4] = {0.0f, 0.0f, 0.0f, 0.0f};
123  gl.TexParameterfv(*target, IMPELLER_GL_TEXTURE_BORDER_COLOR, border_color);
124  }
125 
126  // Anisotropy is a per-texture parameter in GLES, so it must be written on
127  // every configuration (including resetting it back to 1) to prevent a
128  // previously configured value from leaking into this sampler's state. The
129  // parameter only exists when GL_EXT_texture_filter_anisotropic is present;
130  // it is applied with TexParameterfv, which is core ES 2.0.
131  const uint32_t max_anisotropy =
132  gl.GetCapabilities()->GetMaxSamplerAnisotropy();
133  if (max_anisotropy > 1) {
134  const GLfloat anisotropy[1] = {static_cast<GLfloat>(
135  std::clamp<uint32_t>(desc.max_anisotropy, 1u, max_anisotropy))};
136  gl.TexParameterfv(*target, IMPELLER_GL_TEXTURE_MAX_ANISOTROPY, anisotropy);
137  }
138 
139  return true;
140 }
141 
142 } // namespace impeller
const std::shared_ptr< const CapabilitiesGLES > & GetCapabilities() const
const TextureDescriptor & GetTextureDescriptor() const
Definition: texture.cc:55
static GLint ToAddressMode(SamplerAddressMode mode, bool supports_decal_sampler_address_mode)
Definition: sampler_gles.cc:53
SamplerAddressMode
Definition: formats.h:618
static GLint ToParam(MinMagFilter minmag_filter, MipFilter mip_filter)
Definition: sampler_gles.cc:31
MipFilter
Options for selecting and filtering between mipmap levels.
Definition: formats.h:602
constexpr std::optional< GLenum > ToTextureTarget(TextureType type)
Definition: formats_gles.h:204
MinMagFilter
Describes how the texture should be sampled when the texture is being shrunk (minified) or expanded (...
Definition: formats.h:592
#define IMPELLER_GL_TEXTURE_BORDER_COLOR
Definition: gles.h:13
#define IMPELLER_GL_CLAMP_TO_BORDER
Definition: gles.h:12
#define IMPELLER_GL_TEXTURE_MAX_ANISOTROPY
Definition: gles.h:16
SamplerAddressMode width_address_mode
SamplerAddressMode height_address_mode