summaryrefslogtreecommitdiffstats
path: root/gpu
diff options
context:
space:
mode:
authordongseong.hwang@intel.com <dongseong.hwang@intel.com@0039d316-1c4b-4281-b951-d872f2087c98>2014-08-13 02:51:57 +0000
committerdongseong.hwang@intel.com <dongseong.hwang@intel.com@0039d316-1c4b-4281-b951-d872f2087c98>2014-08-13 02:53:15 +0000
commit90f7d30d54c49306adf4aa591226b9c14a72081f (patch)
tree9f3793064158bba17264159766965c9b449ab9cc /gpu
parent34beae1545678c03fe1d4898c6941b76aa6c1bc7 (diff)
downloadchromium_src-90f7d30d54c49306adf4aa591226b9c14a72081f.zip
chromium_src-90f7d30d54c49306adf4aa591226b9c14a72081f.tar.gz
chromium_src-90f7d30d54c49306adf4aa591226b9c14a72081f.tar.bz2
gpu: Optimize and cleanup code used for CHROMIUM_copy_texture.
When source target and destination target is GL_TEXTURE_2D, we can use glCopyTexImage2D() directly. It avoids gl state changes, program binding and drawing call. |dest_target| of DoCopyTexture() is always GL_TEXTURE_2D, so remove the redundant argument. Perf data are as follows: Linux (Intel IvyBridge i7-3520M): 16 us vs 6 us -> 260% faster Android (Nexus 5): 331.8 us vs 252.7 us -> 31% faster BUG=N/A Review URL: https://codereview.chromium.org/374193002 Cr-Commit-Position: refs/heads/master@{#289160} git-svn-id: svn://svn.chromium.org/chrome/trunk/src@289160 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gpu')
-rw-r--r--gpu/GLES2/extensions/CHROMIUM/CHROMIUM_copy_texture.txt13
-rw-r--r--gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc162
-rw-r--r--gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h28
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.cc48
4 files changed, 191 insertions, 60 deletions
diff --git a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_copy_texture.txt b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_copy_texture.txt
index 4431e49..fdaa7d6 100644
--- a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_copy_texture.txt
+++ b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_copy_texture.txt
@@ -47,7 +47,18 @@ New Procedures and Functions
destination texture. The level parameter must be 0 at present.
The internal format of the destination texture is converted to that
- specified by <internal_format>.
+ specified by <internal_format>. Must be one of the following symbolic
+ constants: GL_ALPHA, GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_RGB, GL_RGBA
+ When <source_id> texture doens't contain a superset of the component
+ required by <internal_format>, fill the components by following rules.
+
+ source format color components
+ =================================================
+ GL_ALPHA (0, 0, 0, A)
+ GL_LUMINANCE (L, L, L, 1)
+ GL_LUMINANCE_ALPHA (L, L, L, A)
+ GL_RGB (R, G, B, 1)
+ GL_RGBA (R, G, B, A)
The format type of the destination texture is converted to that specified
by <dest_type>.
diff --git a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
index bda65ac..f98ca2e 100644
--- a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
+++ b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
@@ -167,7 +167,7 @@ FragmentShaderId GetFragmentShaderId(bool premultiply_alpha,
}
NOTREACHED();
- return shader_ids[index][SAMPLER_2D];
+ return shader_ids[0][SAMPLER_2D];
}
void CompileShader(GLuint shader, const char* shader_source) {
@@ -186,6 +186,68 @@ void DeleteShader(GLuint shader) {
glDeleteShader(shader);
}
+bool BindFramebufferTexture2D(GLenum target,
+ GLuint texture_id,
+ GLint level,
+ GLuint framebuffer) {
+ DCHECK(target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE_ARB);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(target, texture_id);
+ // NVidia drivers require texture settings to be a certain way
+ // or they won't report FRAMEBUFFER_COMPLETE.
+ glTexParameterf(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer);
+ glFramebufferTexture2DEXT(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, texture_id, level);
+
+#ifndef NDEBUG
+ GLenum fb_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER);
+ if (GL_FRAMEBUFFER_COMPLETE != fb_status) {
+ DLOG(ERROR) << "CopyTextureCHROMIUM: Incomplete framebuffer.";
+ return false;
+ }
+#endif
+ return true;
+}
+
+void DoCopyTexImage2D(const gpu::gles2::GLES2Decoder* decoder,
+ GLenum source_target,
+ GLuint source_id,
+ GLuint dest_id,
+ GLint dest_level,
+ GLenum dest_internal_format,
+ GLsizei width,
+ GLsizei height,
+ GLuint framebuffer) {
+ DCHECK(source_target == GL_TEXTURE_2D ||
+ source_target == GL_TEXTURE_RECTANGLE_ARB);
+ if (BindFramebufferTexture2D(
+ source_target, source_id, 0 /* level */, framebuffer)) {
+ glBindTexture(GL_TEXTURE_2D, dest_id);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glCopyTexImage2D(GL_TEXTURE_2D,
+ dest_level,
+ dest_internal_format,
+ 0 /* x */,
+ 0 /* y */,
+ width,
+ height,
+ 0 /* border */);
+ }
+
+ decoder->RestoreTextureState(source_id);
+ decoder->RestoreTextureState(dest_id);
+ decoder->RestoreTextureUnitBindings(0);
+ decoder->RestoreActiveTexture();
+ decoder->RestoreFramebufferBindings();
+}
+
} // namespace
namespace gpu {
@@ -197,13 +259,19 @@ CopyTextureCHROMIUMResourceManager::CopyTextureCHROMIUMResourceManager()
buffer_id_(0u),
framebuffer_(0u) {}
-CopyTextureCHROMIUMResourceManager::~CopyTextureCHROMIUMResourceManager() {}
+CopyTextureCHROMIUMResourceManager::~CopyTextureCHROMIUMResourceManager() {
+ DCHECK(!buffer_id_);
+ DCHECK(!framebuffer_);
+}
void CopyTextureCHROMIUMResourceManager::Initialize(
const gles2::GLES2Decoder* decoder) {
COMPILE_ASSERT(
kVertexPositionAttrib == 0u,
Position_attribs_must_be_0);
+ DCHECK(!buffer_id_);
+ DCHECK(!framebuffer_);
+ DCHECK(programs_.empty());
// Initialize all of the GPU resources required to perform the copy.
glGenBuffersARB(1, &buffer_id_);
@@ -227,6 +295,7 @@ void CopyTextureCHROMIUMResourceManager::Destroy() {
return;
glDeleteFramebuffersEXT(1, &framebuffer_);
+ framebuffer_ = 0;
std::for_each(vertex_shaders_.begin(), vertex_shaders_.end(), DeleteShader);
std::for_each(
@@ -239,37 +308,70 @@ void CopyTextureCHROMIUMResourceManager::Destroy() {
}
glDeleteBuffersARB(1, &buffer_id_);
+ buffer_id_ = 0;
}
void CopyTextureCHROMIUMResourceManager::DoCopyTexture(
const gles2::GLES2Decoder* decoder,
GLenum source_target,
- GLenum dest_target,
GLuint source_id,
+ GLenum source_internal_format,
GLuint dest_id,
- GLint level,
+ GLint dest_level,
+ GLenum dest_internal_format,
GLsizei width,
GLsizei height,
bool flip_y,
bool premultiply_alpha,
bool unpremultiply_alpha) {
+ bool premultiply_alpha_change = premultiply_alpha ^ unpremultiply_alpha;
+ // GL_INVALID_OPERATION is generated if the currently bound framebuffer's
+ // format does not contain a superset of the components required by the base
+ // format of internalformat.
+ // https://www.khronos.org/opengles/sdk/docs/man/xhtml/glCopyTexImage2D.xml
+ bool source_format_contain_superset_of_dest_format =
+ source_internal_format == dest_internal_format ||
+ (source_internal_format == GL_RGBA && dest_internal_format == GL_RGB);
+ // GL_TEXTURE_RECTANGLE_ARB on FBO is supported by OpenGL, not GLES2,
+ // so restrict this to GL_TEXTURE_2D.
+ if (source_target == GL_TEXTURE_2D && !flip_y && !premultiply_alpha_change &&
+ source_format_contain_superset_of_dest_format) {
+ DoCopyTexImage2D(decoder,
+ source_target,
+ source_id,
+ dest_id,
+ dest_level,
+ dest_internal_format,
+ width,
+ height,
+ framebuffer_);
+ return;
+ }
+
// Use default transform matrix if no transform passed in.
const static GLfloat default_matrix[16] = {1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f};
- DoCopyTextureWithTransform(decoder, source_target, dest_target, source_id,
- dest_id, level, width, height, flip_y, premultiply_alpha,
- unpremultiply_alpha, default_matrix);
+ DoCopyTextureWithTransform(decoder,
+ source_target,
+ source_id,
+ dest_id,
+ dest_level,
+ width,
+ height,
+ flip_y,
+ premultiply_alpha,
+ unpremultiply_alpha,
+ default_matrix);
}
void CopyTextureCHROMIUMResourceManager::DoCopyTextureWithTransform(
const gles2::GLES2Decoder* decoder,
GLenum source_target,
- GLenum dest_target,
GLuint source_id,
GLuint dest_id,
- GLint level,
+ GLint dest_level,
GLsizei width,
GLsizei height,
bool flip_y,
@@ -286,27 +388,27 @@ void CopyTextureCHROMIUMResourceManager::DoCopyTextureWithTransform(
VertexShaderId vertex_shader_id = GetVertexShaderId(flip_y);
DCHECK_LT(static_cast<size_t>(vertex_shader_id), vertex_shaders_.size());
- GLuint* vertex_shader = &vertex_shaders_[vertex_shader_id];
- if (!*vertex_shader) {
- *vertex_shader = glCreateShader(GL_VERTEX_SHADER);
- CompileShader(*vertex_shader, vertex_shader_source[vertex_shader_id]);
- }
-
FragmentShaderId fragment_shader_id = GetFragmentShaderId(
premultiply_alpha, unpremultiply_alpha, source_target);
DCHECK_LT(static_cast<size_t>(fragment_shader_id), fragment_shaders_.size());
- GLuint* fragment_shader = &fragment_shaders_[fragment_shader_id];
- if (!*fragment_shader) {
- *fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
- CompileShader(*fragment_shader, fragment_shader_source[fragment_shader_id]);
- }
ProgramMapKey key(vertex_shader_id, fragment_shader_id);
ProgramInfo* info = &programs_[key];
// Create program if necessary.
if (!info->program) {
info->program = glCreateProgram();
+ GLuint* vertex_shader = &vertex_shaders_[vertex_shader_id];
+ if (!*vertex_shader) {
+ *vertex_shader = glCreateShader(GL_VERTEX_SHADER);
+ CompileShader(*vertex_shader, vertex_shader_source[vertex_shader_id]);
+ }
glAttachShader(info->program, *vertex_shader);
+ GLuint* fragment_shader = &fragment_shaders_[fragment_shader_id];
+ if (!*fragment_shader) {
+ *fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
+ CompileShader(*fragment_shader,
+ fragment_shader_source[fragment_shader_id]);
+ }
glAttachShader(info->program, *fragment_shader);
glBindAttribLocation(info->program, kVertexPositionAttrib, "a_position");
glLinkProgram(info->program);
@@ -337,25 +439,9 @@ void CopyTextureCHROMIUMResourceManager::DoCopyTextureWithTransform(
glUniform2f(info->half_size_handle, width / 2.0f, height / 2.0f);
else
glUniform2f(info->half_size_handle, 0.5f, 0.5f);
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, dest_id);
- // NVidia drivers require texture settings to be a certain way
- // or they won't report FRAMEBUFFER_COMPLETE.
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer_);
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dest_target,
- dest_id, level);
-#ifndef NDEBUG
- GLenum fb_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER);
- if (GL_FRAMEBUFFER_COMPLETE != fb_status) {
- DLOG(ERROR) << "CopyTextureCHROMIUM: Incomplete framebuffer.";
- } else
-#endif
- {
+ if (BindFramebufferTexture2D(
+ GL_TEXTURE_2D, dest_id, dest_level, framebuffer_)) {
decoder->ClearAllAttributes();
glEnableVertexAttribArray(kVertexPositionAttrib);
diff --git a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h
index 17290f8..083fc4c 100644
--- a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h
+++ b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h
@@ -20,7 +20,8 @@ class GLES2Decoder;
// This class encapsulates the resources required to implement the
// GL_CHROMIUM_copy_texture extension. The copy operation is performed
-// via a blit to a framebuffer object.
+// via glCopyTexImage2D() or a blit to a framebuffer object.
+// The target of |dest_id| texture must be GL_TEXTURE_2D.
class GPU_EXPORT CopyTextureCHROMIUMResourceManager {
public:
CopyTextureCHROMIUMResourceManager();
@@ -29,18 +30,29 @@ class GPU_EXPORT CopyTextureCHROMIUMResourceManager {
void Initialize(const gles2::GLES2Decoder* decoder);
void Destroy();
- void DoCopyTexture(const gles2::GLES2Decoder* decoder, GLenum source_target,
- GLenum dest_target, GLuint source_id, GLuint dest_id,
- GLint level, GLsizei width, GLsizei height,
- bool flip_y, bool premultiply_alpha,
+ void DoCopyTexture(const gles2::GLES2Decoder* decoder,
+ GLenum source_target,
+ GLuint source_id,
+ GLenum source_internal_format,
+ GLuint dest_id,
+ GLint dest_level,
+ GLenum dest_internal_format,
+ GLsizei width,
+ GLsizei height,
+ bool flip_y,
+ bool premultiply_alpha,
bool unpremultiply_alpha);
// This will apply a transform on the source texture before copying to
// destination texture.
void DoCopyTextureWithTransform(const gles2::GLES2Decoder* decoder,
- GLenum source_target, GLenum dest_target,
- GLuint source_id, GLuint dest_id, GLint level,
- GLsizei width, GLsizei height, bool flip_y,
+ GLenum source_target,
+ GLuint source_id,
+ GLuint dest_id,
+ GLint dest_level,
+ GLsizei width,
+ GLsizei height,
+ bool flip_y,
bool premultiply_alpha,
bool unpremultiply_alpha,
const GLfloat transform_matrix[16]);
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 418ca3a..0a7f822 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -10055,6 +10055,11 @@ void GLES2DecoderImpl::DoCopyTextureCHROMIUM(
return;
}
+ GLenum source_type = 0;
+ GLenum source_internal_format = 0;
+ source_texture->GetLevelType(
+ source_texture->target(), 0, &source_type, &source_internal_format);
+
GLenum dest_type_previous = dest_type;
GLenum dest_internal_format = internal_format;
bool dest_level_defined = dest_texture->GetLevelSize(
@@ -10065,6 +10070,20 @@ void GLES2DecoderImpl::DoCopyTextureCHROMIUM(
&dest_internal_format);
}
+ // The destination format should be GL_ALPHA, GL_RGB, GL_RGBA, GL_LUMINANCE,
+ // or GL_LUMINANCE_ALPHA.
+ bool valid_dest_format = dest_internal_format >= GL_ALPHA &&
+ dest_internal_format <= GL_LUMINANCE_ALPHA;
+ // The source format can be GL_BGRA_EXT.
+ bool valid_source_format = (source_internal_format >= GL_ALPHA &&
+ source_internal_format <= GL_LUMINANCE_ALPHA) ||
+ source_internal_format == GL_BGRA_EXT;
+ if (!valid_source_format || !valid_dest_format) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glCopyTextureCHROMIUM", "invalid internal format");
+ return;
+ }
+
// Resize the destination texture to the dimensions of the source texture.
if (!dest_level_defined || dest_width != source_width ||
dest_height != source_height ||
@@ -10105,25 +10124,28 @@ void GLES2DecoderImpl::DoCopyTextureCHROMIUM(
copy_texture_CHROMIUM_->DoCopyTextureWithTransform(
this,
source_texture->target(),
- dest_texture->target(),
source_texture->service_id(),
- dest_texture->service_id(), level,
- source_width, source_height,
+ dest_texture->service_id(),
+ level,
+ source_width,
+ source_height,
unpack_flip_y_,
unpack_premultiply_alpha_,
unpack_unpremultiply_alpha_,
default_matrix);
} else {
- copy_texture_CHROMIUM_->DoCopyTexture(
- this,
- source_texture->target(),
- dest_texture->target(),
- source_texture->service_id(),
- dest_texture->service_id(), level,
- source_width, source_height,
- unpack_flip_y_,
- unpack_premultiply_alpha_,
- unpack_unpremultiply_alpha_);
+ copy_texture_CHROMIUM_->DoCopyTexture(this,
+ source_texture->target(),
+ source_texture->service_id(),
+ source_internal_format,
+ dest_texture->service_id(),
+ level,
+ internal_format,
+ source_width,
+ source_height,
+ unpack_flip_y_,
+ unpack_premultiply_alpha_,
+ unpack_unpremultiply_alpha_);
}
DoDidUseTexImageIfNeeded(source_texture, source_texture->target());