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