blob: f061b6f41d0a20104c841f6be531e77e657ca120 [file] [log] [blame]
// Copyright (c) 2013 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_COMMON_GL_HELPER_SCALING_H_
#define COMPONENTS_VIZ_COMMON_GL_HELPER_SCALING_H_
#include <map>
#include <vector>
#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "components/viz/common/gl_helper.h"
#include "components/viz/common/viz_common_export.h"
#include "ui/gfx/geometry/vector2d.h"
namespace viz {
class ShaderProgram;
class ScalerImpl;
class GLHelperTest;
// Implements GPU texture scaling methods.
// Note that you should probably not use this class directly.
// See gl_helper.cc::CreateScaler instead.
class VIZ_COMMON_EXPORT GLHelperScaling {
public:
enum ShaderType {
SHADER_BILINEAR,
SHADER_BILINEAR2,
SHADER_BILINEAR3,
SHADER_BILINEAR4,
SHADER_BILINEAR2X2,
SHADER_BICUBIC_UPSCALE,
SHADER_BICUBIC_HALF_1D,
SHADER_PLANAR,
SHADER_YUV_MRT_PASS1,
SHADER_YUV_MRT_PASS2,
};
using ShaderProgramKeyType = std::pair<ShaderType, bool>;
GLHelperScaling(gpu::gles2::GLES2Interface* gl, GLHelper* helper);
~GLHelperScaling();
void InitBuffer();
// Returns null on invalid arguments.
std::unique_ptr<GLHelper::ScalerInterface> CreateScaler(
GLHelper::ScalerQuality quality,
const gfx::Vector2d& scale_from,
const gfx::Vector2d& scale_to,
bool flipped_source,
bool flip_output,
bool swizzle);
// These convert source textures with RGBA pixel data into a single-color-
// channel planar format. Used for grayscale and I420 format conversion.
//
// While these output RGBA pixels in the destination texture(s), each RGBA
// pixel is actually a container for 4 consecutive pixels in the result.
std::unique_ptr<GLHelper::ScalerInterface> CreateGrayscalePlanerizer(
bool flipped_source,
bool flip_output,
bool swizzle);
std::unique_ptr<GLHelper::ScalerInterface> CreateI420Planerizer(
int plane, // 0=Y, 1=U, 2=V
bool flipped_source,
bool flip_output,
bool swizzle);
// These are a faster path to I420 planerization, if the platform supports
// it. The first pass draws to two outputs simultaneously: the Y plane and an
// interim UV plane that is used as the input to the second pass. Then, the
// second pass splits the UV plane, drawing to two outputs: the final U plane
// and final V plane. Thus, clients should call ScaleToMultipleOutputs() on
// the returned instance.
std::unique_ptr<GLHelper::ScalerInterface> CreateI420MrtPass1Planerizer(
bool flipped_source,
bool flip_output,
bool swizzle);
std::unique_ptr<GLHelper::ScalerInterface> CreateI420MrtPass2Planerizer(
bool swizzle);
private:
// A ScaleOp represents a pass in a scaler pipeline, in one dimension.
// Note that when quality is GOOD, multiple scaler passes will be
// combined into one operation for increased performance.
// Exposed in the header file for testing purposes.
struct ScaleOp {
ScaleOp(int factor, bool x, int size)
: scale_factor(factor), scale_x(x), scale_size(size) {}
// Calculates the sequence of ScaleOp needed to convert an image of
// relative size |src| into an image of relative size |dst|. If |scale_x| is
// true, then the calculations are for the X axis of the image, otherwise Y.
// If |allow3| is true, we can use a SHADER_BILINEAR3 to replace
// a scale up and scale down with a 3-tap bilinear scale.
// The calculated ScaleOps are added to |ops|.
static void AddOps(int src,
int dst,
bool scale_x,
bool allow3,
base::circular_deque<ScaleOp>* ops) {
int num_downscales = 0;
if (allow3 && dst * 3 >= src && dst * 2 < src) {
// Technically, this should be a scale up and then a
// scale down, but it makes the optimization code more
// complicated.
ops->push_back(ScaleOp(3, scale_x, dst));
return;
}
while ((dst << num_downscales) < src) {
num_downscales++;
}
if ((dst << num_downscales) != src) {
ops->push_back(ScaleOp(0, scale_x, dst << num_downscales));
}
while (num_downscales) {
num_downscales--;
ops->push_back(ScaleOp(2, scale_x, dst << num_downscales));
}
}
// Update either the X or Y component of |scale| to the match the relative
// result size of this ScaleOp.
void UpdateScale(gfx::Vector2d* scale) {
if (scale_x) {
scale->set_x(scale_size);
} else {
scale->set_y(scale_size);
}
}
// A scale factor of 0 means upscale
// 2 means 50% scale
// 3 means 33% scale, etc.
int scale_factor;
bool scale_x; // Otherwise y
int scale_size; // Size to scale to.
};
// Full specification for a single scaling stage.
struct ScalerStage {
ShaderType shader;
gfx::Vector2d scale_from;
gfx::Vector2d scale_to;
bool scale_x;
bool flipped_source;
bool flip_output;
bool swizzle;
};
// Compute a vector of scaler stages for a particular
// set of input/output parameters.
static void ComputeScalerStages(GLHelper::ScalerQuality quality,
const gfx::Vector2d& scale_from,
const gfx::Vector2d& scale_to,
bool flipped_source,
bool flip_output,
bool swizzle,
std::vector<ScalerStage>* scaler_stages);
// Take two queues of ScaleOp structs and generate a
// vector of scaler stages. This is the second half of
// ComputeScalerStages.
static void ConvertScalerOpsToScalerStages(
GLHelper::ScalerQuality quality,
gfx::Vector2d scale_from,
base::circular_deque<GLHelperScaling::ScaleOp>* x_ops,
base::circular_deque<GLHelperScaling::ScaleOp>* y_ops,
std::vector<ScalerStage>* scaler_stages);
scoped_refptr<ShaderProgram> GetShaderProgram(ShaderType type, bool swizzle);
// Interleaved array of 2-dimentional vertex positions (x, y) and
// 2-dimentional texture coordinates (s, t).
static const GLfloat kVertexAttributes[];
gpu::gles2::GLES2Interface* gl_;
GLHelper* helper_;
// The buffer that holds the vertices and the texture coordinates data for
// drawing a quad.
ScopedBuffer vertex_attributes_buffer_;
std::map<ShaderProgramKeyType, scoped_refptr<ShaderProgram>> shader_programs_;
friend class ShaderProgram;
friend class ScalerImpl;
friend class GLHelperBenchmark;
friend class GLHelperTest;
DISALLOW_COPY_AND_ASSIGN(GLHelperScaling);
};
} // namespace viz
#endif // COMPONENTS_VIZ_COMMON_GL_HELPER_SCALING_H_