blob: 2a8fb9f5484768f88ec6d383639da2d42fd777fd [file] [log] [blame]
// Copyright 2011 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.
#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_PROGRAM_BINDING_H_
#define COMPONENTS_VIZ_SERVICE_DISPLAY_PROGRAM_BINDING_H_
#include <string>
#include "base/logging.h"
#include "base/macros.h"
#include "build/build_config.h"
#include "components/viz/common/gpu/context_provider.h"
#include "components/viz/service/display/shader.h"
#include "components/viz/service/viz_service_export.h"
namespace gfx {
class ColorTransform;
}
namespace gpu {
namespace gles2 {
class GLES2Interface;
}
} // namespace gpu
namespace viz {
class VIZ_SERVICE_EXPORT ProgramBindingBase {
public:
ProgramBindingBase();
~ProgramBindingBase();
bool Init(gpu::gles2::GLES2Interface* context,
const std::string& vertex_shader,
const std::string& fragment_shader);
bool Link(gpu::gles2::GLES2Interface* context);
void Cleanup(gpu::gles2::GLES2Interface* context);
unsigned program() const { return program_; }
bool initialized() const { return initialized_; }
protected:
unsigned LoadShader(gpu::gles2::GLES2Interface* context,
unsigned type,
const std::string& shader_source);
unsigned CreateShaderProgram(gpu::gles2::GLES2Interface* context,
unsigned vertex_shader,
unsigned fragment_shader);
void CleanupShaders(gpu::gles2::GLES2Interface* context);
bool IsContextLost(gpu::gles2::GLES2Interface* context);
unsigned program_;
unsigned vertex_shader_id_;
unsigned fragment_shader_id_;
bool initialized_;
private:
DISALLOW_COPY_AND_ASSIGN(ProgramBindingBase);
};
enum ProgramType {
PROGRAM_TYPE_DEBUG_BORDER,
PROGRAM_TYPE_SOLID_COLOR,
PROGRAM_TYPE_TILE,
PROGRAM_TYPE_TEXTURE,
PROGRAM_TYPE_RENDER_PASS,
PROGRAM_TYPE_VIDEO_STREAM,
PROGRAM_TYPE_YUV_VIDEO,
};
class VIZ_SERVICE_EXPORT ProgramKey {
public:
ProgramKey();
ProgramKey(const ProgramKey& other);
~ProgramKey();
static ProgramKey DebugBorder();
static ProgramKey SolidColor(AAMode aa_mode, bool tint_color);
static ProgramKey Tile(TexCoordPrecision precision,
SamplerType sampler,
AAMode aa_mode,
SwizzleMode swizzle_mode,
PremultipliedAlphaMode premultiplied_alpha,
bool is_opaque,
bool has_tex_clamp_rect,
bool tint_color);
static ProgramKey Texture(TexCoordPrecision precision,
SamplerType sampler,
PremultipliedAlphaMode premultiplied_alpha,
bool has_background_color,
bool has_tex_clamp_rect,
bool tint_color);
// TODO(ccameron): Merge |mask_for_background| into MaskMode.
static ProgramKey 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);
static ProgramKey VideoStream(TexCoordPrecision precision);
static ProgramKey YUVVideo(TexCoordPrecision precision,
SamplerType sampler,
YUVAlphaTextureMode yuv_alpha_texture_mode,
UVTextureMode uv_texture_mode,
bool tint_color);
bool operator==(const ProgramKey& other) const;
bool operator!=(const ProgramKey& other) const;
void SetColorTransform(const gfx::ColorTransform* transform);
bool has_output_color_matrix() const { return has_output_color_matrix_; }
void set_has_output_color_matrix(bool value) {
has_output_color_matrix_ = value;
}
TexCoordPrecision tex_coord_precision() const { return precision_; }
private:
friend struct ProgramKeyHash;
friend class Program;
ProgramType type_ = PROGRAM_TYPE_DEBUG_BORDER;
TexCoordPrecision precision_ = TEX_COORD_PRECISION_NA;
SamplerType sampler_ = SAMPLER_TYPE_NA;
BlendMode blend_mode_ = BLEND_MODE_NONE;
AAMode aa_mode_ = NO_AA;
SwizzleMode swizzle_mode_ = NO_SWIZZLE;
bool is_opaque_ = false;
PremultipliedAlphaMode premultiplied_alpha_ = PREMULTIPLIED_ALPHA;
bool has_background_color_ = false;
MaskMode mask_mode_ = NO_MASK;
bool mask_for_background_ = false;
bool has_color_matrix_ = false;
YUVAlphaTextureMode yuv_alpha_texture_mode_ = YUV_NO_ALPHA_TEXTURE;
UVTextureMode uv_texture_mode_ = UV_TEXTURE_MODE_NA;
ColorConversionMode color_conversion_mode_ = COLOR_CONVERSION_MODE_NONE;
const gfx::ColorTransform* color_transform_ = nullptr;
bool has_tex_clamp_rect_ = false;
bool has_output_color_matrix_ = false;
bool has_tint_color_matrix_ = false;
};
struct ProgramKeyHash {
size_t operator()(const ProgramKey& key) const {
return (static_cast<size_t>(key.type_) << 0) ^
(static_cast<size_t>(key.precision_) << 3) ^
(static_cast<size_t>(key.sampler_) << 6) ^
(static_cast<size_t>(key.blend_mode_) << 9) ^
(static_cast<size_t>(key.aa_mode_) << 15) ^
(static_cast<size_t>(key.swizzle_mode_) << 16) ^
(static_cast<size_t>(key.is_opaque_) << 17) ^
(static_cast<size_t>(key.premultiplied_alpha_) << 19) ^
(static_cast<size_t>(key.has_background_color_) << 20) ^
(static_cast<size_t>(key.mask_mode_) << 21) ^
(static_cast<size_t>(key.mask_for_background_) << 22) ^
(static_cast<size_t>(key.has_color_matrix_) << 23) ^
(static_cast<size_t>(key.yuv_alpha_texture_mode_) << 24) ^
(static_cast<size_t>(key.uv_texture_mode_) << 25) ^
(static_cast<size_t>(key.color_conversion_mode_) << 26) ^
(static_cast<size_t>(key.has_tex_clamp_rect_) << 28) ^
(static_cast<size_t>(key.has_output_color_matrix_) << 29) ^
(static_cast<size_t>(key.has_tint_color_matrix_) << 30);
}
};
class VIZ_SERVICE_EXPORT Program : public ProgramBindingBase {
public:
Program() {}
void Initialize(ContextProvider* context_provider, const ProgramKey& key) {
// Set parameters that are common to all sub-classes.
vertex_shader_.aa_mode_ = key.aa_mode_;
fragment_shader_.aa_mode_ = key.aa_mode_;
fragment_shader_.blend_mode_ = key.blend_mode_;
fragment_shader_.tex_coord_precision_ = key.precision_;
fragment_shader_.sampler_type_ = key.sampler_;
fragment_shader_.swizzle_mode_ = key.swizzle_mode_;
fragment_shader_.premultiply_alpha_mode_ = key.premultiplied_alpha_;
fragment_shader_.mask_mode_ = key.mask_mode_;
fragment_shader_.mask_for_background_ = key.mask_for_background_;
fragment_shader_.color_conversion_mode_ = key.color_conversion_mode_;
fragment_shader_.color_transform_ = key.color_transform_;
fragment_shader_.has_output_color_matrix_ = key.has_output_color_matrix_;
fragment_shader_.has_tint_color_matrix_ = key.has_tint_color_matrix_;
switch (key.type_) {
case PROGRAM_TYPE_DEBUG_BORDER:
InitializeDebugBorderProgram();
break;
case PROGRAM_TYPE_SOLID_COLOR:
InitializeSolidColorProgram(key);
break;
case PROGRAM_TYPE_TILE:
InitializeTileProgram(key);
break;
case PROGRAM_TYPE_TEXTURE:
InitializeTextureProgram(key);
break;
case PROGRAM_TYPE_RENDER_PASS:
InitializeRenderPassProgram(key);
break;
case PROGRAM_TYPE_VIDEO_STREAM:
InitializeVideoStreamProgram(key);
break;
case PROGRAM_TYPE_YUV_VIDEO:
InitializeYUVVideo(key);
break;
}
InitializeInternal(context_provider);
}
const VertexShader& vertex_shader() const { return vertex_shader_; }
const FragmentShader& fragment_shader() const { return fragment_shader_; }
// Functions for querying uniform locations.
int vertex_tex_transform_location() const {
return vertex_shader_.vertex_tex_transform_location_;
}
int tex_matrix_location() const {
return vertex_shader_.tex_matrix_location_;
}
int ya_tex_scale_location() const {
return vertex_shader_.ya_tex_scale_location_;
}
int ya_tex_offset_location() const {
return vertex_shader_.ya_tex_offset_location_;
}
int uv_tex_scale_location() const {
return vertex_shader_.uv_tex_scale_location_;
}
int uv_tex_offset_location() const {
return vertex_shader_.uv_tex_offset_location_;
}
int matrix_location() const { return vertex_shader_.matrix_location_; }
int vertex_opacity_location() const {
return vertex_shader_.vertex_opacity_location_;
}
int viewport_location() const { return vertex_shader_.viewport_location_; }
int edge_location() const { return vertex_shader_.edge_location_; }
int quad_location() const { return vertex_shader_.quad_location_; }
int sampler_location() const { return fragment_shader_.sampler_location_; }
int alpha_location() const { return fragment_shader_.alpha_location_; }
int color_location() const { return fragment_shader_.color_location_; }
int background_color_location() const {
return fragment_shader_.background_color_location_;
}
int fragment_tex_transform_location() const {
return fragment_shader_.fragment_tex_transform_location_;
}
int backdrop_location() const { return fragment_shader_.backdrop_location_; }
int backdrop_rect_location() const {
return fragment_shader_.backdrop_rect_location_;
}
int original_backdrop_location() const {
return fragment_shader_.original_backdrop_location_;
}
int mask_sampler_location() const {
return fragment_shader_.mask_sampler_location_;
}
int mask_tex_coord_scale_location() const {
return fragment_shader_.mask_tex_coord_scale_location_;
}
int mask_tex_coord_offset_location() const {
return fragment_shader_.mask_tex_coord_offset_location_;
}
int color_matrix_location() const {
return fragment_shader_.color_matrix_location_;
}
int color_offset_location() const {
return fragment_shader_.color_offset_location_;
}
int tex_clamp_rect_location() const {
return fragment_shader_.tex_clamp_rect_location_;
}
int y_texture_location() const {
return fragment_shader_.y_texture_location_;
}
int u_texture_location() const {
return fragment_shader_.u_texture_location_;
}
int v_texture_location() const {
return fragment_shader_.v_texture_location_;
}
int uv_texture_location() const {
return fragment_shader_.uv_texture_location_;
}
int a_texture_location() const {
return fragment_shader_.a_texture_location_;
}
int lut_texture_location() const {
return fragment_shader_.lut_texture_location_;
}
int lut_size_location() const { return fragment_shader_.lut_size_location_; }
int resource_multiplier_location() const {
return fragment_shader_.resource_multiplier_location_;
}
int resource_offset_location() const {
return fragment_shader_.resource_offset_location_;
}
int ya_clamp_rect_location() const {
return fragment_shader_.ya_clamp_rect_location_;
}
int uv_clamp_rect_location() const {
return fragment_shader_.uv_clamp_rect_location_;
}
int output_color_matrix_location() const {
return fragment_shader_.output_color_matrix_location_;
}
int tint_color_matrix_location() const {
return fragment_shader_.tint_color_matrix_location_;
}
private:
void InitializeDebugBorderProgram() {
// Initialize fragment program.
fragment_shader_.input_color_type_ = INPUT_COLOR_SOURCE_UNIFORM;
fragment_shader_.frag_color_mode_ = FRAG_COLOR_MODE_DEFAULT;
}
void InitializeSolidColorProgram(const ProgramKey& key) {
// Initialize vertex program.
vertex_shader_.position_source_ = POSITION_SOURCE_ATTRIBUTE_INDEXED_UNIFORM;
#if defined(OS_ANDROID)
if (key.aa_mode_ == NO_AA)
vertex_shader_.has_dummy_variables_ = true;
#endif
// Initialize fragment program.
fragment_shader_.input_color_type_ = INPUT_COLOR_SOURCE_UNIFORM;
fragment_shader_.frag_color_mode_ = FRAG_COLOR_MODE_DEFAULT;
}
void InitializeTileProgram(const ProgramKey& key) {
// Initialize vertex program.
vertex_shader_.position_source_ = POSITION_SOURCE_ATTRIBUTE_INDEXED_UNIFORM;
vertex_shader_.tex_coord_transform_ = TEX_COORD_TRANSFORM_VEC4;
vertex_shader_.tex_coord_source_ = TEX_COORD_SOURCE_ATTRIBUTE;
// Initialize fragment program.
fragment_shader_.has_tex_clamp_rect_ = key.has_tex_clamp_rect_;
if (key.is_opaque_) {
DCHECK_EQ(key.aa_mode_, NO_AA);
fragment_shader_.frag_color_mode_ = FRAG_COLOR_MODE_OPAQUE;
} else {
// TODO(ccameron): This branch shouldn't be needed (this is always
// BLEND_MODE_NONE).
if (key.aa_mode_ == NO_AA && key.swizzle_mode_ == NO_SWIZZLE)
fragment_shader_.frag_color_mode_ = FRAG_COLOR_MODE_APPLY_BLEND_MODE;
fragment_shader_.has_uniform_alpha_ = true;
}
// AA changes the texture coordinate mode (affecting both shaders).
if (key.aa_mode_ == USE_AA) {
vertex_shader_.tex_coord_source_ = TEX_COORD_SOURCE_POSITION;
vertex_shader_.aa_mode_ = USE_AA;
fragment_shader_.has_rgba_fragment_tex_transform_ = true;
// Tiles that have AA do their own clamping.
DCHECK(!fragment_shader_.has_tex_clamp_rect_);
}
}
void InitializeTextureProgram(const ProgramKey& key) {
// Initialize vertex program.
vertex_shader_.tex_coord_source_ = TEX_COORD_SOURCE_ATTRIBUTE;
vertex_shader_.tex_coord_transform_ = TEX_COORD_TRANSFORM_VEC4;
vertex_shader_.has_vertex_opacity_ = true;
vertex_shader_.use_uniform_arrays_ = !key.has_tex_clamp_rect_;
// Initialize fragment program.
fragment_shader_.has_varying_alpha_ = true;
fragment_shader_.has_background_color_ = key.has_background_color_;
fragment_shader_.has_tex_clamp_rect_ = key.has_tex_clamp_rect_;
}
void InitializeRenderPassProgram(const ProgramKey& key) {
// Initialize vertex program.
if (key.aa_mode_ == NO_AA) {
vertex_shader_.tex_coord_source_ = TEX_COORD_SOURCE_ATTRIBUTE;
vertex_shader_.tex_coord_transform_ = TEX_COORD_TRANSFORM_VEC4;
vertex_shader_.has_vertex_opacity_ = true;
vertex_shader_.use_uniform_arrays_ = true;
} else {
vertex_shader_.position_source_ =
POSITION_SOURCE_ATTRIBUTE_INDEXED_UNIFORM;
vertex_shader_.tex_coord_source_ = TEX_COORD_SOURCE_POSITION;
vertex_shader_.tex_coord_transform_ = TEX_COORD_TRANSFORM_TRANSLATED_VEC4;
}
// Initialize fragment program.
fragment_shader_.frag_color_mode_ = FRAG_COLOR_MODE_APPLY_BLEND_MODE;
fragment_shader_.has_uniform_alpha_ = true;
fragment_shader_.has_color_matrix_ = key.has_color_matrix_;
if (key.mask_mode_ == HAS_MASK) {
fragment_shader_.ignore_sampler_type_ = true;
} else {
DCHECK(!key.mask_for_background_);
}
}
void InitializeVideoStreamProgram(const ProgramKey& key) {
vertex_shader_.tex_coord_source_ = TEX_COORD_SOURCE_ATTRIBUTE;
vertex_shader_.tex_coord_transform_ = TEX_COORD_TRANSFORM_MATRIX;
DCHECK_EQ(key.sampler_, SAMPLER_TYPE_EXTERNAL_OES);
}
void InitializeYUVVideo(const ProgramKey& key) {
vertex_shader_.tex_coord_source_ = TEX_COORD_SOURCE_ATTRIBUTE;
vertex_shader_.is_ya_uv_ = true;
fragment_shader_.input_color_type_ = INPUT_COLOR_SOURCE_YUV_TEXTURES;
fragment_shader_.has_uniform_alpha_ = true;
fragment_shader_.yuv_alpha_texture_mode_ = key.yuv_alpha_texture_mode_;
fragment_shader_.uv_texture_mode_ = key.uv_texture_mode_;
}
void InitializeInternal(ContextProvider* context_provider) {
DCHECK(context_provider);
DCHECK(!initialized_);
if (IsContextLost(context_provider->ContextGL()))
return;
if (!ProgramBindingBase::Init(context_provider->ContextGL(),
vertex_shader_.GetShaderString(),
fragment_shader_.GetShaderString())) {
DCHECK(IsContextLost(context_provider->ContextGL()));
return;
}
int base_uniform_index = 0;
vertex_shader_.Init(context_provider->ContextGL(), program_,
&base_uniform_index);
fragment_shader_.Init(context_provider->ContextGL(), program_,
&base_uniform_index);
// Link after binding uniforms
if (!Link(context_provider->ContextGL())) {
DCHECK(IsContextLost(context_provider->ContextGL()));
return;
}
initialized_ = true;
}
VertexShader vertex_shader_;
FragmentShader fragment_shader_;
DISALLOW_COPY_AND_ASSIGN(Program);
};
} // namespace viz
#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_PROGRAM_BINDING_H_