Commit 032c6a30 authored by reveman@chromium.org's avatar reveman@chromium.org

gpu: Refactor and cleanup CHROMIUM_copy_texture implementation.

This removes duplicate shader code, makes it easier to support
additional texture targets and implements on demand initialization
of shaders.

BUG=366710

Review URL: https://codereview.chromium.org/255763002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@266351 0039d316-1c4b-4281-b951-d872f2087c98
parent a4b3d6b5
......@@ -10,19 +10,19 @@
#include "gpu/command_buffer/service/gl_utils.h"
#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
#define SHADER0(src) \
"#ifdef GL_ES\n"\
"precision mediump float;\n"\
"#endif\n"\
#src
#define SHADER(src) { false, SHADER0(src), }
#define SHADER_EXTERNAL_OES0(src) \
"#extension GL_OES_EGL_image_external : require\n"\
"#ifdef GL_ES\n"\
"precision mediump float;\n"\
"#endif\n"\
#src
#define SHADER_EXTERNAL_OES(src) { true, SHADER_EXTERNAL_OES0(src), }
#define SHADER(src) \
"#ifdef GL_ES\n" \
"precision mediump float;\n" \
"#endif\n" #src
#define SHADER_2D(src) \
"#define SamplerType sampler2D\n" \
"#define TextureLookup texture2D\n" SHADER(src)
#define SHADER_EXTERNAL_OES(src) \
"#extension GL_OES_EGL_image_external : require\n" \
"#define SamplerType samplerExternalOES\n" \
"#define TextureLookup texture2D\n" SHADER(src)
#define SHADERS(src) \
{ SHADER_2D(src), SHADER_EXTERNAL_OES(src) }
namespace {
......@@ -31,28 +31,23 @@ const GLfloat kQuadVertices[] = { -1.0f, -1.0f, 0.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f,
-1.0f, 1.0f, 0.0f, 1.0f };
enum ProgramId {
PROGRAM_COPY_TEXTURE,
PROGRAM_COPY_TEXTURE_FLIP_Y,
PROGRAM_COPY_TEXTURE_PREMULTIPLY_ALPHA,
PROGRAM_COPY_TEXTURE_UNPREMULTIPLY_ALPHA,
PROGRAM_COPY_TEXTURE_PREMULTIPLY_ALPHA_FLIPY,
PROGRAM_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_FLIPY,
PROGRAM_COPY_TEXTURE_OES,
PROGRAM_COPY_TEXTURE_OES_FLIP_Y,
PROGRAM_COPY_TEXTURE_OES_PREMULTIPLY_ALPHA,
PROGRAM_COPY_TEXTURE_OES_UNPREMULTIPLY_ALPHA,
PROGRAM_COPY_TEXTURE_OES_PREMULTIPLY_ALPHA_FLIPY,
PROGRAM_COPY_TEXTURE_OES_UNPREMULTIPLY_ALPHA_FLIPY,
enum ShaderId {
SHADER_COPY_TEXTURE,
SHADER_COPY_TEXTURE_FLIP_Y,
SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA,
SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA,
SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_FLIP_Y,
SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_FLIP_Y,
NUM_SHADERS,
};
struct ShaderInfo {
bool needs_egl_image_external;
const char* source;
enum SamplerId {
SAMPLER_TEXTURE_2D,
SAMPLER_TEXTURE_EXTERNAL_OES,
NUM_SAMPLERS,
};
const ShaderInfo shader_infos[] = {
// VERTEX_SHADER_POS_TEX
const char* vertex_shader_source =
SHADER(
uniform mat4 u_matrix;
attribute vec4 a_position;
......@@ -60,123 +55,64 @@ const ShaderInfo shader_infos[] = {
void main(void) {
gl_Position = u_matrix * a_position;
v_uv = a_position.xy * 0.5 + vec2(0.5, 0.5);
}),
// FRAGMENT_SHADER_TEX
SHADER(
uniform sampler2D u_texSampler;
varying vec2 v_uv;
void main(void) {
gl_FragColor = texture2D(u_texSampler, v_uv.st);
}),
// FRAGMENT_SHADER_TEX_FLIP_Y
SHADER(
uniform sampler2D u_texSampler;
varying vec2 v_uv;
void main(void) {
gl_FragColor = texture2D(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
}),
// FRAGMENT_SHADER_TEX_PREMULTIPLY_ALPHA
SHADER(
uniform sampler2D u_texSampler;
varying vec2 v_uv;
void main(void) {
gl_FragColor = texture2D(u_texSampler, v_uv.st);
gl_FragColor.rgb *= gl_FragColor.a;
}),
// FRAGMENT_SHADER_TEX_UNPREMULTIPLY_ALPHA
SHADER(
uniform sampler2D u_texSampler;
varying vec2 v_uv;
void main(void) {
gl_FragColor = texture2D(u_texSampler, v_uv.st);
if (gl_FragColor.a > 0.0)
gl_FragColor.rgb /= gl_FragColor.a;
}),
// FRAGMENT_SHADER_TEX_PREMULTIPLY_ALPHA_FLIP_Y
SHADER(
uniform sampler2D u_texSampler;
varying vec2 v_uv;
void main(void) {
gl_FragColor = texture2D(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
gl_FragColor.rgb *= gl_FragColor.a;
}),
// FRAGMENT_SHADER_TEX_UNPREMULTIPLY_ALPHA_FLIP_Y
SHADER(
uniform sampler2D u_texSampler;
varying vec2 v_uv;
void main(void) {
gl_FragColor = texture2D(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
if (gl_FragColor.a > 0.0)
gl_FragColor.rgb /= gl_FragColor.a;
}),
// FRAGMENT_SHADER_TEX_OES
SHADER_EXTERNAL_OES(
precision mediump float;
uniform samplerExternalOES u_texSampler;
});
const char* fragment_shader_source[NUM_SHADERS][NUM_SAMPLERS] = {
// SHADER_COPY_TEXTURE
SHADERS(
uniform SamplerType u_texSampler;
varying vec2 v_uv;
void main(void) {
gl_FragColor = texture2D(u_texSampler, v_uv.st);
gl_FragColor = TextureLookup(u_texSampler, v_uv.st);
}),
// FRAGMENT_SHADER_TEX_OES_FLIP_Y
SHADER_EXTERNAL_OES(
precision mediump float;
uniform samplerExternalOES u_texSampler;
// SHADER_COPY_TEXTURE_FLIP_Y
SHADERS(
uniform SamplerType u_texSampler;
varying vec2 v_uv;
void main(void) {
gl_FragColor =
texture2D(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
gl_FragColor = TextureLookup(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
}),
// FRAGMENT_SHADER_TEX_OES_PREMULTIPLY_ALPHA
SHADER_EXTERNAL_OES(
precision mediump float;
uniform samplerExternalOES u_texSampler;
// SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA
SHADERS(
uniform SamplerType u_texSampler;
varying vec2 v_uv;
void main(void) {
gl_FragColor = texture2D(u_texSampler, v_uv.st);
gl_FragColor = TextureLookup(u_texSampler, v_uv.st);
gl_FragColor.rgb *= gl_FragColor.a;
}),
// FRAGMENT_SHADER_TEX_OES_UNPREMULTIPLY_ALPHA
SHADER_EXTERNAL_OES(
precision mediump float;
uniform samplerExternalOES u_texSampler;
// SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA
SHADERS(
uniform SamplerType u_texSampler;
varying vec2 v_uv;
void main(void) {
gl_FragColor = texture2D(u_texSampler, v_uv.st);
gl_FragColor = TextureLookup(u_texSampler, v_uv.st);
if (gl_FragColor.a > 0.0)
gl_FragColor.rgb /= gl_FragColor.a;
}),
// FRAGMENT_SHADER_TEX_OES_PREMULTIPLY_ALPHA_FLIP_Y
SHADER_EXTERNAL_OES(
precision mediump float;
uniform samplerExternalOES u_texSampler;
// SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_FLIP_Y
SHADERS(
uniform SamplerType u_texSampler;
varying vec2 v_uv;
void main(void) {
gl_FragColor =
texture2D(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
gl_FragColor = TextureLookup(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
gl_FragColor.rgb *= gl_FragColor.a;
}),
// FRAGMENT_SHADER_TEX_OES_UNPREMULTIPLY_ALPHA_FLIP_Y
SHADER_EXTERNAL_OES(
precision mediump float;
uniform samplerExternalOES u_texSampler;
// SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_FLIP_Y
SHADERS(
uniform SamplerType u_texSampler;
varying vec2 v_uv;
void main(void) {
gl_FragColor =
texture2D(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
gl_FragColor = TextureLookup(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
if (gl_FragColor.a > 0.0)
gl_FragColor.rgb /= gl_FragColor.a;
}),
};
const int kNumShaders = arraysize(shader_infos);
// Returns the correct program to evaluate the copy operation for
// Returns the correct shader id to evaluate the copy operation for
// the CHROMIUM_flipy and premultiply alpha pixel store settings.
ProgramId GetProgram(
bool flip_y,
ShaderId GetShaderId(bool flip_y,
bool premultiply_alpha,
bool unpremultiply_alpha,
bool is_source_external_oes) {
bool unpremultiply_alpha) {
// If both pre-multiply and unpremultiply are requested, then perform no
// alpha manipulation.
if (premultiply_alpha && unpremultiply_alpha) {
......@@ -187,31 +123,44 @@ ProgramId GetProgram(
// bit 0: Flip_y
// bit 1: Premult
// bit 2: Unpremult
// bit 3: External_oes
static ProgramId program_ids[] = {
PROGRAM_COPY_TEXTURE,
PROGRAM_COPY_TEXTURE_FLIP_Y, // F
PROGRAM_COPY_TEXTURE_PREMULTIPLY_ALPHA, // P
PROGRAM_COPY_TEXTURE_PREMULTIPLY_ALPHA_FLIPY, // F P
PROGRAM_COPY_TEXTURE_UNPREMULTIPLY_ALPHA, // U
PROGRAM_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_FLIPY, // F U
PROGRAM_COPY_TEXTURE, // P U
PROGRAM_COPY_TEXTURE, // F P U
PROGRAM_COPY_TEXTURE_OES, // E
PROGRAM_COPY_TEXTURE_OES_FLIP_Y, // F E
PROGRAM_COPY_TEXTURE_OES_PREMULTIPLY_ALPHA, // P E
PROGRAM_COPY_TEXTURE_OES_PREMULTIPLY_ALPHA_FLIPY, // F P E
PROGRAM_COPY_TEXTURE_OES_UNPREMULTIPLY_ALPHA, // U E
PROGRAM_COPY_TEXTURE_OES_UNPREMULTIPLY_ALPHA_FLIPY, // F U E
PROGRAM_COPY_TEXTURE_OES, // P U E
PROGRAM_COPY_TEXTURE_OES, // F P U E
static ShaderId shader_ids[] = {
SHADER_COPY_TEXTURE,
SHADER_COPY_TEXTURE_FLIP_Y, // F
SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA, // P
SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_FLIP_Y, // F P
SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA, // U
SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_FLIP_Y, // F U
SHADER_COPY_TEXTURE, // P U
SHADER_COPY_TEXTURE_FLIP_Y, // F P U
};
unsigned index = (flip_y ? (1 << 0) : 0) |
(premultiply_alpha ? (1 << 1) : 0) |
(unpremultiply_alpha ? (1 << 2) : 0) |
(is_source_external_oes ? (1 << 3) : 0);
return program_ids[index];
(unpremultiply_alpha ? (1 << 2) : 0);
return shader_ids[index];
}
SamplerId GetSamplerId(GLenum source_target) {
switch (source_target) {
case GL_TEXTURE_2D:
return SAMPLER_TEXTURE_2D;
case GL_TEXTURE_EXTERNAL_OES:
return SAMPLER_TEXTURE_EXTERNAL_OES;
}
NOTREACHED();
return SAMPLER_TEXTURE_2D;
}
void CompileShader(GLuint shader, const char* shader_source) {
glShaderSource(shader, 1, &shader_source, 0);
glCompileShader(shader);
#ifndef NDEBUG
GLint compile_status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
if (GL_TRUE != compile_status)
DLOG(ERROR) << "CopyTextureCHROMIUM: shader compilation failure.";
#endif
}
} // namespace
......@@ -219,27 +168,17 @@ ProgramId GetProgram(
namespace gpu {
CopyTextureCHROMIUMResourceManager::CopyTextureCHROMIUMResourceManager()
: initialized_(false),
buffer_id_(0),
framebuffer_(0) {
for (int i = 0; i < kNumPrograms; ++i) {
programs_[i] = 0;
matrix_handle_[i] = 0;
sampler_locations_[i] = 0;
}
: initialized_(false), buffer_id_(0), framebuffer_(0), vertex_shader_(0) {
}
CopyTextureCHROMIUMResourceManager::~CopyTextureCHROMIUMResourceManager() {}
void CopyTextureCHROMIUMResourceManager::Initialize(
const gles2::GLES2Decoder* decoder) {
COMPILE_ASSERT(
kVertexPositionAttrib == 0u,
Position_attribs_must_be_0);
const char* extensions =
reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
bool have_egl_image_external = extensions &&
strstr(extensions, "GL_OES_EGL_image_external");
// Initialize all of the GPU resources required to perform the copy.
glGenBuffersARB(1, &buffer_id_);
glBindBuffer(GL_ARRAY_BUFFER, buffer_id_);
......@@ -248,56 +187,8 @@ void CopyTextureCHROMIUMResourceManager::Initialize(
glGenFramebuffersEXT(1, &framebuffer_);
// TODO(gman): Init these on demand.
GLuint shaders[kNumShaders];
for (int shader = 0; shader < kNumShaders; ++shader) {
shaders[shader] = glCreateShader(
shader == 0 ? GL_VERTEX_SHADER : GL_FRAGMENT_SHADER);
const ShaderInfo& info = shader_infos[shader];
if (info.needs_egl_image_external && !have_egl_image_external) {
continue;
}
const char* shader_source = shader_infos[shader].source;
glShaderSource(shaders[shader], 1, &shader_source, 0);
glCompileShader(shaders[shader]);
#ifndef NDEBUG
GLint compile_status;
glGetShaderiv(shaders[shader], GL_COMPILE_STATUS, &compile_status);
if (GL_TRUE != compile_status)
DLOG(ERROR) << "CopyTextureCHROMIUM: shader compilation failure.";
#endif
}
// TODO(gman): Init these on demand.
for (int program = 0; program < kNumPrograms; ++program) {
const ShaderInfo& info = shader_infos[program + 1];
if (info.needs_egl_image_external && !have_egl_image_external) {
continue;
}
programs_[program] = glCreateProgram();
glAttachShader(programs_[program], shaders[0]);
glAttachShader(programs_[program], shaders[program + 1]);
glBindAttribLocation(programs_[program], kVertexPositionAttrib,
"a_position");
glLinkProgram(programs_[program]);
#ifndef NDEBUG
GLint linked;
glGetProgramiv(programs_[program], GL_LINK_STATUS, &linked);
if (!linked)
DLOG(ERROR) << "CopyTextureCHROMIUM: program link failure.";
#endif
sampler_locations_[program] = glGetUniformLocation(programs_[program],
"u_texSampler");
matrix_handle_[program] = glGetUniformLocation(programs_[program],
"u_matrix");
}
for (int shader = 0; shader < kNumShaders; ++shader)
glDeleteShader(shaders[shader]);
vertex_shader_ = glCreateShader(GL_VERTEX_SHADER);
CompileShader(vertex_shader_, vertex_shader_source);
decoder->RestoreBufferBindings();
......@@ -310,9 +201,11 @@ void CopyTextureCHROMIUMResourceManager::Destroy() {
glDeleteFramebuffersEXT(1, &framebuffer_);
for (int program = 0; program < kNumPrograms; ++program) {
if (programs_[program])
glDeleteProgram(programs_[program]);
glDeleteShader(vertex_shader_);
for (ProgramMap::const_iterator it = programs_.begin(); it != programs_.end();
++it) {
const ProgramInfo& info = it->second;
glDeleteProgram(info.program);
}
glDeleteBuffersARB(1, &buffer_id_);
......@@ -360,22 +253,45 @@ void CopyTextureCHROMIUMResourceManager::DoCopyTextureWithTransform(
return;
}
GLuint program = GetProgram(
flip_y, premultiply_alpha, unpremultiply_alpha,
source_target == GL_TEXTURE_EXTERNAL_OES);
glUseProgram(programs_[program]);
ShaderId shader_id =
GetShaderId(flip_y, premultiply_alpha, unpremultiply_alpha);
SamplerId sampler_id = GetSamplerId(source_target);
ProgramMapKey key(shader_id, sampler_id);
ProgramInfo* info = &programs_[key];
// Create program if necessary.
if (!info->program) {
GLuint shader = glCreateShader(GL_FRAGMENT_SHADER);
CompileShader(shader, fragment_shader_source[shader_id][sampler_id]);
info->program = glCreateProgram();
glAttachShader(info->program, vertex_shader_);
glAttachShader(info->program, shader);
glBindAttribLocation(info->program, kVertexPositionAttrib, "a_position");
glLinkProgram(info->program);
#ifndef NDEBUG
GLint linked;
glGetProgramiv(info->program, GL_LINK_STATUS, &linked);
if (!linked)
DLOG(ERROR) << "CopyTextureCHROMIUM: program link failure.";
#endif
info->sampler_locations =
glGetUniformLocation(info->program, "u_texSampler");
info->matrix_handle = glGetUniformLocation(info->program, "u_matrix");
glDeleteShader(shader);
}
glUseProgram(info->program);
#ifndef NDEBUG
glValidateProgram(programs_[program]);
glValidateProgram(info->program);
GLint validation_status;
glGetProgramiv(programs_[program], GL_VALIDATE_STATUS, &validation_status);
glGetProgramiv(info->program, GL_VALIDATE_STATUS, &validation_status);
if (GL_TRUE != validation_status) {
DLOG(ERROR) << "CopyTextureCHROMIUM: Invalid shader.";
return;
}
#endif
glUniformMatrix4fv(matrix_handle_[program], 1, GL_FALSE, transform_matrix);
glUniformMatrix4fv(info->matrix_handle, 1, GL_FALSE, transform_matrix);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, dest_id);
// NVidia drivers require texture settings to be a certain way
......@@ -402,7 +318,7 @@ void CopyTextureCHROMIUMResourceManager::DoCopyTextureWithTransform(
glVertexAttribPointer(kVertexPositionAttrib, 4, GL_FLOAT, GL_FALSE,
4 * sizeof(GLfloat), 0);
glUniform1i(sampler_locations_[program], 0);
glUniform1i(info->sampler_locations, 0);
glBindTexture(source_target, source_id);
glTexParameterf(source_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
......
......@@ -5,6 +5,7 @@
#ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_COPY_TEXTURE_CHROMIUM_H_
#define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_COPY_TEXTURE_CHROMIUM_H_
#include "base/containers/hash_tables.h"
#include "gpu/command_buffer/service/gl_utils.h"
#include "gpu/gpu_export.h"
......@@ -21,6 +22,7 @@ class GLES2Decoder;
class GPU_EXPORT CopyTextureCHROMIUMResourceManager {
public:
CopyTextureCHROMIUMResourceManager();
~CopyTextureCHROMIUMResourceManager();
void Initialize(const gles2::GLES2Decoder* decoder);
void Destroy();
......@@ -45,14 +47,21 @@ class GPU_EXPORT CopyTextureCHROMIUMResourceManager {
static const GLuint kVertexPositionAttrib = 0;
private:
bool initialized_;
struct ProgramInfo {
ProgramInfo() : program(0u), matrix_handle(0u), sampler_locations(0u) {}
GLuint program;
GLuint matrix_handle;
GLuint sampler_locations;
};
static const int kNumPrograms = 12;
GLuint programs_[kNumPrograms];
bool initialized_;
typedef std::pair<int, int> ProgramMapKey;
typedef base::hash_map<ProgramMapKey, ProgramInfo> ProgramMap;
ProgramMap programs_;
GLuint buffer_id_;
GLuint framebuffer_;
GLuint matrix_handle_[kNumPrograms];
GLuint sampler_locations_[kNumPrograms];
GLuint vertex_shader_;
DISALLOW_COPY_AND_ASSIGN(CopyTextureCHROMIUMResourceManager);
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment