1 // Copyright 2011 The Chromium 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 
5 #include "components/viz/service/display/program_binding.h"
6 
7 #include "base/logging.h"
8 #include "base/trace_event/trace_event.h"
9 #include "components/viz/service/display/geometry_binding.h"
10 #include "gpu/GLES2/gl2extchromium.h"
11 #include "gpu/command_buffer/client/gles2_interface.h"
12 #include "ui/gfx/color_transform.h"
13 
14 using gpu::gles2::GLES2Interface;
15 
16 namespace viz {
17 
18 ProgramKey::ProgramKey() = default;
19 
20 ProgramKey::ProgramKey(const ProgramKey& other) = default;
21 
22 ProgramKey::~ProgramKey() = default;
23 
operator ==(const ProgramKey & other) const24 bool ProgramKey::operator==(const ProgramKey& other) const {
25   return type_ == other.type_ && precision_ == other.precision_ &&
26          sampler_ == other.sampler_ && blend_mode_ == other.blend_mode_ &&
27          aa_mode_ == other.aa_mode_ && is_opaque_ == other.is_opaque_ &&
28          premultiplied_alpha_ == other.premultiplied_alpha_ &&
29          has_background_color_ == other.has_background_color_ &&
30          has_tex_clamp_rect_ == other.has_tex_clamp_rect_ &&
31          mask_mode_ == other.mask_mode_ &&
32          mask_for_background_ == other.mask_for_background_ &&
33          has_color_matrix_ == other.has_color_matrix_ &&
34          yuv_alpha_texture_mode_ == other.yuv_alpha_texture_mode_ &&
35          uv_texture_mode_ == other.uv_texture_mode_ &&
36          color_conversion_mode_ == other.color_conversion_mode_ &&
37          color_transform_ == other.color_transform_ &&
38          has_output_color_matrix_ == other.has_output_color_matrix_ &&
39          has_rounded_corner_ == other.has_rounded_corner_;
40 }
41 
operator !=(const ProgramKey & other) const42 bool ProgramKey::operator!=(const ProgramKey& other) const {
43   return !(*this == other);
44 }
45 
46 // static
DebugBorder()47 ProgramKey ProgramKey::DebugBorder() {
48   ProgramKey result;
49   result.type_ = PROGRAM_TYPE_DEBUG_BORDER;
50   return result;
51 }
52 
53 // static
SolidColor(AAMode aa_mode,bool tint_color,bool rounded_corner)54 ProgramKey ProgramKey::SolidColor(AAMode aa_mode,
55                                   bool tint_color,
56                                   bool rounded_corner) {
57   ProgramKey result;
58   result.type_ = PROGRAM_TYPE_SOLID_COLOR;
59   result.aa_mode_ = aa_mode;
60   result.has_tint_color_matrix_ = tint_color;
61   result.has_rounded_corner_ = rounded_corner;
62   return result;
63 }
64 
65 // static
Tile(TexCoordPrecision precision,SamplerType sampler,AAMode aa_mode,PremultipliedAlphaMode premultiplied_alpha,bool is_opaque,bool has_tex_clamp_rect,bool tint_color,bool rounded_corner)66 ProgramKey ProgramKey::Tile(TexCoordPrecision precision,
67                             SamplerType sampler,
68                             AAMode aa_mode,
69                             PremultipliedAlphaMode premultiplied_alpha,
70                             bool is_opaque,
71                             bool has_tex_clamp_rect,
72                             bool tint_color,
73                             bool rounded_corner) {
74   ProgramKey result;
75   result.type_ = PROGRAM_TYPE_TILE;
76   result.precision_ = precision;
77   result.sampler_ = sampler;
78   result.aa_mode_ = aa_mode;
79   result.is_opaque_ = is_opaque;
80   result.has_tex_clamp_rect_ = has_tex_clamp_rect;
81   result.has_tint_color_matrix_ = tint_color;
82   result.premultiplied_alpha_ = premultiplied_alpha;
83   result.has_rounded_corner_ = rounded_corner;
84   return result;
85 }
86 
87 // static
Texture(TexCoordPrecision precision,SamplerType sampler,PremultipliedAlphaMode premultiplied_alpha,bool has_background_color,bool has_tex_clamp_rect,bool tint_color,bool rounded_corner)88 ProgramKey ProgramKey::Texture(TexCoordPrecision precision,
89                                SamplerType sampler,
90                                PremultipliedAlphaMode premultiplied_alpha,
91                                bool has_background_color,
92                                bool has_tex_clamp_rect,
93                                bool tint_color,
94                                bool rounded_corner) {
95   ProgramKey result;
96   result.type_ = PROGRAM_TYPE_TEXTURE;
97   result.precision_ = precision;
98   result.sampler_ = sampler;
99   result.premultiplied_alpha_ = premultiplied_alpha;
100   result.has_background_color_ = has_background_color;
101   result.has_tex_clamp_rect_ = has_tex_clamp_rect;
102   result.has_tint_color_matrix_ = tint_color;
103   result.has_rounded_corner_ = rounded_corner;
104   return result;
105 }
106 
107 // static
RenderPass(TexCoordPrecision precision,SamplerType sampler,BlendMode blend_mode,AAMode aa_mode,MaskMode mask_mode,bool mask_for_background,bool has_color_matrix,bool tint_color,bool rounded_corner)108 ProgramKey ProgramKey::RenderPass(TexCoordPrecision precision,
109                                   SamplerType sampler,
110                                   BlendMode blend_mode,
111                                   AAMode aa_mode,
112                                   MaskMode mask_mode,
113                                   bool mask_for_background,
114                                   bool has_color_matrix,
115                                   bool tint_color,
116                                   bool rounded_corner) {
117   ProgramKey result;
118   result.type_ = PROGRAM_TYPE_RENDER_PASS;
119   result.precision_ = precision;
120   result.sampler_ = sampler;
121   result.blend_mode_ = blend_mode;
122   result.aa_mode_ = aa_mode;
123   result.mask_mode_ = mask_mode;
124   result.mask_for_background_ = mask_for_background;
125   result.has_color_matrix_ = has_color_matrix;
126   result.has_tint_color_matrix_ = tint_color;
127   result.has_rounded_corner_ = rounded_corner;
128   return result;
129 }
130 
131 // static
VideoStream(TexCoordPrecision precision,bool rounded_corner)132 ProgramKey ProgramKey::VideoStream(TexCoordPrecision precision,
133                                    bool rounded_corner) {
134   ProgramKey result;
135   result.type_ = PROGRAM_TYPE_VIDEO_STREAM;
136   result.precision_ = precision;
137   result.sampler_ = SAMPLER_TYPE_EXTERNAL_OES;
138   result.has_rounded_corner_ = rounded_corner;
139   return result;
140 }
141 
142 // static
YUVVideo(TexCoordPrecision precision,SamplerType sampler,YUVAlphaTextureMode yuv_alpha_texture_mode,UVTextureMode uv_texture_mode,bool tint_color,bool rounded_corner)143 ProgramKey ProgramKey::YUVVideo(TexCoordPrecision precision,
144                                 SamplerType sampler,
145                                 YUVAlphaTextureMode yuv_alpha_texture_mode,
146                                 UVTextureMode uv_texture_mode,
147                                 bool tint_color,
148                                 bool rounded_corner) {
149   ProgramKey result;
150   result.type_ = PROGRAM_TYPE_YUV_VIDEO;
151   result.precision_ = precision;
152   result.sampler_ = sampler;
153   result.yuv_alpha_texture_mode_ = yuv_alpha_texture_mode;
154   DCHECK(yuv_alpha_texture_mode == YUV_NO_ALPHA_TEXTURE ||
155          yuv_alpha_texture_mode == YUV_HAS_ALPHA_TEXTURE);
156   result.uv_texture_mode_ = uv_texture_mode;
157   DCHECK(uv_texture_mode == UV_TEXTURE_MODE_UV ||
158          uv_texture_mode == UV_TEXTURE_MODE_U_V);
159   result.has_tint_color_matrix_ = tint_color;
160   result.has_rounded_corner_ = rounded_corner;
161   return result;
162 }
163 
SetColorTransform(const gfx::ColorTransform * transform)164 void ProgramKey::SetColorTransform(const gfx::ColorTransform* transform) {
165   color_transform_ = nullptr;
166   if (transform->IsIdentity()) {
167     color_conversion_mode_ = COLOR_CONVERSION_MODE_NONE;
168   } else {
169     color_conversion_mode_ = COLOR_CONVERSION_MODE_SHADER;
170     color_transform_ = transform;
171   }
172 }
173 
ProgramBindingBase()174 ProgramBindingBase::ProgramBindingBase()
175     : program_(0),
176       vertex_shader_id_(0),
177       fragment_shader_id_(0),
178       initialized_(false) {}
179 
~ProgramBindingBase()180 ProgramBindingBase::~ProgramBindingBase() {
181   // If you hit these asserts, you initialized but forgot to call Cleanup().
182   DCHECK(!program_);
183   DCHECK(!vertex_shader_id_);
184   DCHECK(!fragment_shader_id_);
185   DCHECK(!initialized_);
186 }
187 
Init(GLES2Interface * context,const std::string & vertex_shader,const std::string & fragment_shader)188 bool ProgramBindingBase::Init(GLES2Interface* context,
189                               const std::string& vertex_shader,
190                               const std::string& fragment_shader) {
191   TRACE_EVENT0("viz", "ProgramBindingBase::init");
192   vertex_shader_id_ = LoadShader(context, GL_VERTEX_SHADER, vertex_shader);
193   if (!vertex_shader_id_)
194     return false;
195 
196   fragment_shader_id_ =
197       LoadShader(context, GL_FRAGMENT_SHADER, fragment_shader);
198   if (!fragment_shader_id_) {
199     context->DeleteShader(vertex_shader_id_);
200     vertex_shader_id_ = 0;
201     return false;
202   }
203 
204   program_ =
205       CreateShaderProgram(context, vertex_shader_id_, fragment_shader_id_);
206   return !!program_;
207 }
208 
Link(GLES2Interface * context)209 bool ProgramBindingBase::Link(GLES2Interface* context) {
210   context->LinkProgram(program_);
211   CleanupShaders(context);
212   if (!program_)
213     return false;
214 #ifndef NDEBUG
215   int linked = 0;
216   context->GetProgramiv(program_, GL_LINK_STATUS, &linked);
217   if (!linked) {
218     char buffer[1024] = "";
219     context->GetProgramInfoLog(program_, sizeof(buffer), nullptr, buffer);
220     DLOG(ERROR) << "Error compiling shader: " << buffer;
221     return false;
222   }
223 #endif
224   return true;
225 }
226 
Cleanup(GLES2Interface * context)227 void ProgramBindingBase::Cleanup(GLES2Interface* context) {
228   initialized_ = false;
229   if (!program_)
230     return;
231 
232   DCHECK(context);
233   context->DeleteProgram(program_);
234   program_ = 0;
235 
236   CleanupShaders(context);
237 }
238 
LoadShader(GLES2Interface * context,unsigned type,const std::string & shader_source)239 unsigned ProgramBindingBase::LoadShader(GLES2Interface* context,
240                                         unsigned type,
241                                         const std::string& shader_source) {
242   unsigned shader = context->CreateShader(type);
243   if (!shader)
244     return 0u;
245 
246   const char* shader_source_str[] = {shader_source.data()};
247   int shader_length[] = {static_cast<int>(shader_source.length())};
248   context->ShaderSource(shader, 1, shader_source_str, shader_length);
249   context->CompileShader(shader);
250 #if DCHECK_IS_ON()
251   int compiled = 0;
252   context->GetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
253   if (!compiled) {
254     char buffer[1024] = "";
255     context->GetShaderInfoLog(shader, sizeof(buffer), nullptr, buffer);
256     DLOG(ERROR) << "Error compiling shader: " << buffer
257                 << "\n shader program: " << shader_source;
258     return 0u;
259   }
260 #endif
261   return shader;
262 }
263 
CreateShaderProgram(GLES2Interface * context,unsigned vertex_shader,unsigned fragment_shader)264 unsigned ProgramBindingBase::CreateShaderProgram(GLES2Interface* context,
265                                                  unsigned vertex_shader,
266                                                  unsigned fragment_shader) {
267   unsigned program_object = context->CreateProgram();
268   if (!program_object)
269     return 0;
270 
271   context->AttachShader(program_object, vertex_shader);
272   context->AttachShader(program_object, fragment_shader);
273 
274   // Bind the common attrib locations.
275   context->BindAttribLocation(
276       program_object, GeometryBinding::PositionAttribLocation(), "a_position");
277   context->BindAttribLocation(
278       program_object, GeometryBinding::TexCoordAttribLocation(), "a_texCoord");
279   context->BindAttribLocation(program_object,
280                               GeometryBinding::TriangleIndexAttribLocation(),
281                               "a_index");
282 
283   return program_object;
284 }
285 
CleanupShaders(GLES2Interface * context)286 void ProgramBindingBase::CleanupShaders(GLES2Interface* context) {
287   if (vertex_shader_id_) {
288     context->DeleteShader(vertex_shader_id_);
289     vertex_shader_id_ = 0;
290   }
291   if (fragment_shader_id_) {
292     context->DeleteShader(fragment_shader_id_);
293     fragment_shader_id_ = 0;
294   }
295 }
296 
IsContextLost(GLES2Interface * context)297 bool ProgramBindingBase::IsContextLost(GLES2Interface* context) {
298   return context->GetGraphicsResetStatusKHR() != GL_NO_ERROR;
299 }
300 
301 }  // namespace viz
302