Chromium Code Reviews| Index: gpu/command_buffer/service/gles2_cmd_decoder.cc | 
| diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc | 
| index f28cc4387e7832e07bdf8335f303ff646fd0293c..25e33abb51b1f8fdceb28f72f560c568c146ab02 100644 | 
| --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc | 
| +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc | 
| @@ -983,6 +983,12 @@ class GLES2DecoderImpl : public GLES2Decoder, public ErrorStateClient { | 
| void DoCompressedCopyTextureCHROMIUM(GLuint source_id, GLuint dest_id); | 
| + // Helper for DoTexStorage2DEXT and DoTexStorage3D. | 
| + void TexStorageImpl( | 
| + GLenum target, GLint levels, GLenum internal_format, | 
| + GLsizei width, GLsizei height, GLsizei depth, | 
| + ContextState::Dimension dimension, const char* function_name); | 
| + | 
| // Wrapper for TexStorage2DEXT. | 
| void DoTexStorage2DEXT( | 
| GLenum target, | 
| @@ -8823,12 +8829,36 @@ void GLES2DecoderImpl::DoGetSamplerParameteriv( | 
| void GLES2DecoderImpl::DoGetTexParameterfv( | 
| GLenum target, GLenum pname, GLfloat* params) { | 
| InitTextureMaxAnisotropyIfNeeded(target, pname); | 
| + if (pname == GL_TEXTURE_IMMUTABLE_FORMAT && | 
| + feature_info_->gl_version_info().IsLowerThanGL(4, 2) && | 
| + !features().ext_texture_storage) { | 
| 
 
piman
2016/04/11 22:59:31
I'm not sure when that condition would be true. GL
 
Zhenyao Mo
2016/04/11 23:17:19
This will be removed for option 2.
 
 | 
| + // We emulate TexStorage calls in such situations. | 
| + TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget( | 
| + &state_, target); | 
| + if (texture_ref) { | 
| + Texture* texture = texture_ref->texture(); | 
| + *params = static_cast<GLfloat>(texture->IsImmutable()); | 
| + return; | 
| + } | 
| + } | 
| glGetTexParameterfv(target, pname, params); | 
| } | 
| void GLES2DecoderImpl::DoGetTexParameteriv( | 
| GLenum target, GLenum pname, GLint* params) { | 
| InitTextureMaxAnisotropyIfNeeded(target, pname); | 
| + if (pname == GL_TEXTURE_IMMUTABLE_FORMAT && | 
| + feature_info_->gl_version_info().IsLowerThanGL(4, 2) && | 
| + !features().ext_texture_storage) { | 
| + // We emulate TexStorage calls in such situations. | 
| + TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget( | 
| + &state_, target); | 
| + if (texture_ref) { | 
| + Texture* texture = texture_ref->texture(); | 
| + *params = static_cast<GLint>(texture->IsImmutable()); | 
| + return; | 
| + } | 
| + } | 
| glGetTexParameteriv(target, pname, params); | 
| } | 
| @@ -14298,143 +14328,65 @@ void GLES2DecoderImpl::DoCompressedCopyTextureCHROMIUM(GLuint source_id, | 
| false, false); | 
| } | 
| -void GLES2DecoderImpl::DoTexStorage2DEXT( | 
| - GLenum target, | 
| - GLint levels, | 
| - GLenum internal_format, | 
| - GLsizei width, | 
| - GLsizei height) { | 
| - TRACE_EVENT2("gpu", "GLES2DecoderImpl::DoTexStorage2DEXT", | 
| - "width", width, "height", height); | 
| - if (!texture_manager()->ValidForTarget(target, 0, width, height, 1) || | 
| - TextureManager::ComputeMipMapCount(target, width, height, 1) < levels) { | 
| - LOCAL_SET_GL_ERROR( | 
| - GL_INVALID_VALUE, "glTexStorage2DEXT", "dimensions out of range"); | 
| - return; | 
| - } | 
| - TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget( | 
| - &state_, target); | 
| - if (!texture_ref) { | 
| - LOCAL_SET_GL_ERROR( | 
| - GL_INVALID_OPERATION, | 
| - "glTexStorage2DEXT", "unknown texture for target"); | 
| - return; | 
| - } | 
| - Texture* texture = texture_ref->texture(); | 
| - if (texture->IsAttachedToFramebuffer()) { | 
| - framebuffer_state_.clear_state_dirty = true; | 
| - } | 
| - if (texture->IsImmutable()) { | 
| - LOCAL_SET_GL_ERROR( | 
| - GL_INVALID_OPERATION, | 
| - "glTexStorage2DEXT", "texture is immutable"); | 
| - return; | 
| - } | 
| - | 
| - GLenum format = TextureManager::ExtractFormatFromStorageFormat( | 
| - internal_format); | 
| - GLenum type = TextureManager::ExtractTypeFromStorageFormat(internal_format); | 
| - | 
| - { | 
| - GLsizei level_width = width; | 
| - GLsizei level_height = height; | 
| - uint32_t estimated_size = 0; | 
| - for (int ii = 0; ii < levels; ++ii) { | 
| - uint32_t level_size = 0; | 
| - if (!GLES2Util::ComputeImageDataSizes( | 
| - level_width, level_height, 1, format, type, state_.unpack_alignment, | 
| - &estimated_size, NULL, NULL) || | 
| - !SafeAddUint32(estimated_size, level_size, &estimated_size)) { | 
| - LOCAL_SET_GL_ERROR( | 
| - GL_OUT_OF_MEMORY, "glTexStorage2DEXT", "dimensions too large"); | 
| - return; | 
| - } | 
| - level_width = std::max(1, level_width >> 1); | 
| - level_height = std::max(1, level_height >> 1); | 
| - } | 
| - if (!EnsureGPUMemoryAvailable(estimated_size)) { | 
| - LOCAL_SET_GL_ERROR( | 
| - GL_OUT_OF_MEMORY, "glTexStorage2DEXT", "out of memory"); | 
| +void GLES2DecoderImpl::TexStorageImpl( | 
| + GLenum target, GLint levels, GLenum internal_format, | 
| + GLsizei width, GLsizei height, GLsizei depth, | 
| + ContextState::Dimension dimension, const char* function_name) { | 
| + if (dimension == ContextState::k2D) { | 
| + if (!validators_->texture_bind_target.IsValid(target)) { | 
| + LOCAL_SET_GL_ERROR_INVALID_ENUM(function_name, target, "target"); | 
| return; | 
| } | 
| - } | 
| - | 
| - LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("glTexStorage2DEXT"); | 
| - glTexStorage2DEXT(target, levels, internal_format, width, height); | 
| - GLenum error = LOCAL_PEEK_GL_ERROR("glTexStorage2DEXT"); | 
| - if (error == GL_NO_ERROR) { | 
| - GLsizei level_width = width; | 
| - GLsizei level_height = height; | 
| - | 
| - GLenum cur_format = feature_info_->IsES3Enabled() ? | 
| - internal_format : format; | 
| - for (int ii = 0; ii < levels; ++ii) { | 
| - if (target == GL_TEXTURE_CUBE_MAP) { | 
| - for (int jj = 0; jj < 6; ++jj) { | 
| - GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X + jj; | 
| - texture_manager()->SetLevelInfo(texture_ref, face, ii, cur_format, | 
| - level_width, level_height, 1, 0, | 
| - format, type, gfx::Rect()); | 
| - } | 
| - } else { | 
| - texture_manager()->SetLevelInfo(texture_ref, target, ii, cur_format, | 
| - level_width, level_height, 1, 0, | 
| - format, type, gfx::Rect()); | 
| - } | 
| - level_width = std::max(1, level_width >> 1); | 
| - level_height = std::max(1, level_height >> 1); | 
| + } else { | 
| + if (!validators_->texture_3_d_target.IsValid(target)) { | 
| + LOCAL_SET_GL_ERROR_INVALID_ENUM(function_name, target, "target"); | 
| + return; | 
| } | 
| - texture->SetImmutable(true); | 
| - } | 
| -} | 
| - | 
| -void GLES2DecoderImpl::DoTexStorage3D( | 
| - GLenum target, | 
| - GLint levels, | 
| - GLenum internal_format, | 
| - GLsizei width, | 
| - GLsizei height, | 
| - GLsizei depth) { | 
| - TRACE_EVENT2("gpu", "GLES2DecoderImpl::DoTexStorage3D", | 
| - "widthXheight", width * height, "depth", depth); | 
| - if (!validators_->texture_3_d_target.IsValid(target)) { | 
| - LOCAL_SET_GL_ERROR_INVALID_ENUM("glTexStorage3D", target, "target"); | 
| - return; | 
| } | 
| if (levels <= 0) { | 
| - LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glTexStorage3D", "levels <= 0"); | 
| + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, function_name, "levels <= 0"); | 
| return; | 
| } | 
| if (!validators_->texture_internal_format_storage.IsValid(internal_format)) { | 
| - LOCAL_SET_GL_ERROR_INVALID_ENUM("glTexStorage3D", internal_format, | 
| - "internal_format"); | 
| - return; | 
| - } | 
| - if (width <= 0) { | 
| - LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glTexStorage3D", "width <= 0"); | 
| - return; | 
| - } | 
| - if (height <= 0) { | 
| - LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glTexStorage3D", "height <= 0"); | 
| + LOCAL_SET_GL_ERROR_INVALID_ENUM( | 
| + function_name, internal_format, "internal_format"); | 
| return; | 
| } | 
| - if (depth <= 0) { | 
| - LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glTexStorage3D", "depth <= 0"); | 
| - return; | 
| + bool is_compressed_format; | 
| + switch (internal_format) { | 
| + case GL_COMPRESSED_R11_EAC: | 
| + case GL_COMPRESSED_SIGNED_R11_EAC: | 
| + case GL_COMPRESSED_RG11_EAC: | 
| + case GL_COMPRESSED_SIGNED_RG11_EAC: | 
| + case GL_COMPRESSED_RGB8_ETC2: | 
| + case GL_COMPRESSED_SRGB8_ETC2: | 
| + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: | 
| + case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: | 
| + case GL_COMPRESSED_RGBA8_ETC2_EAC: | 
| + case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: | 
| + is_compressed_format = true; | 
| + if (target == GL_TEXTURE_3D) { | 
| + LOCAL_SET_GL_ERROR( | 
| + GL_INVALID_OPERATION, function_name, "target invalid for format"); | 
| + return; | 
| + } | 
| + break; | 
| + default: | 
| + is_compressed_format = false; | 
| + break; | 
| } | 
| if (!texture_manager()->ValidForTarget(target, 0, width, height, depth) || | 
| TextureManager::ComputeMipMapCount( | 
| target, width, height, depth) < levels) { | 
| LOCAL_SET_GL_ERROR( | 
| - GL_INVALID_VALUE, "glTexStorage3D", "dimensions out of range"); | 
| + GL_INVALID_VALUE, function_name, "dimensions out of range"); | 
| return; | 
| } | 
| TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget( | 
| &state_, target); | 
| if (!texture_ref) { | 
| LOCAL_SET_GL_ERROR( | 
| - GL_INVALID_OPERATION, | 
| - "glTexStorage3D", "unknown texture for target"); | 
| + GL_INVALID_OPERATION, function_name, "unknown texture for target"); | 
| return; | 
| } | 
| Texture* texture = texture_ref->texture(); | 
| @@ -14443,7 +14395,7 @@ void GLES2DecoderImpl::DoTexStorage3D( | 
| } | 
| if (texture->IsImmutable()) { | 
| LOCAL_SET_GL_ERROR( | 
| - GL_INVALID_OPERATION, "glTexStorage3D", "texture is immutable"); | 
| + GL_INVALID_OPERATION, function_name, "texture is immutable"); | 
| return; | 
| } | 
| @@ -14451,48 +14403,140 @@ void GLES2DecoderImpl::DoTexStorage3D( | 
| internal_format); | 
| GLenum type = TextureManager::ExtractTypeFromStorageFormat(internal_format); | 
| + std::vector<int32_t> level_size(levels); | 
| { | 
| GLsizei level_width = width; | 
| GLsizei level_height = height; | 
| GLsizei level_depth = depth; | 
| - uint32_t estimated_size = 0; | 
| + base::CheckedNumeric<uint32_t> estimated_size(0); | 
| + PixelStoreParams params; | 
| + params.alignment = 1; | 
| for (int ii = 0; ii < levels; ++ii) { | 
| - uint32_t level_size = 0; | 
| - if (!GLES2Util::ComputeImageDataSizes( | 
| - level_width, level_height, level_depth, format, type, | 
| - state_.unpack_alignment, | 
| - &estimated_size, NULL, NULL) || | 
| - !SafeAddUint32(estimated_size, level_size, &estimated_size)) { | 
| - LOCAL_SET_GL_ERROR( | 
| - GL_OUT_OF_MEMORY, "glTexStorage3D", "dimensions too large"); | 
| - return; | 
| + uint32_t size; | 
| + if (is_compressed_format) { | 
| + if (!GetCompressedTexSizeInBytes(function_name, | 
| + level_width, level_height, level_depth, | 
| + internal_format, &level_size[ii])) { | 
| + // GetCompressedTexSizeInBytes() already generates a GL error. | 
| + return; | 
| + } | 
| + size = static_cast<uint32_t>(level_size[ii]); | 
| + } else { | 
| + if (!GLES2Util::ComputeImageDataSizesES3(level_width, | 
| + level_height, | 
| + level_depth, | 
| + format, type, | 
| + params, | 
| + &size, | 
| + nullptr, nullptr, | 
| + nullptr, nullptr)) { | 
| + LOCAL_SET_GL_ERROR( | 
| + GL_OUT_OF_MEMORY, function_name, "dimensions too large"); | 
| + return; | 
| + } | 
| } | 
| + estimated_size += size; | 
| level_width = std::max(1, level_width >> 1); | 
| level_height = std::max(1, level_height >> 1); | 
| if (target == GL_TEXTURE_3D) | 
| level_depth = std::max(1, level_depth >> 1); | 
| } | 
| - if (!EnsureGPUMemoryAvailable(estimated_size)) { | 
| - LOCAL_SET_GL_ERROR( | 
| - GL_OUT_OF_MEMORY, "glTexStorage3D", "out of memory"); | 
| + if (!estimated_size.IsValid() || | 
| + !EnsureGPUMemoryAvailable(estimated_size.ValueOrDefault(0))) { | 
| + LOCAL_SET_GL_ERROR(GL_OUT_OF_MEMORY, function_name, "out of memory"); | 
| return; | 
| } | 
| } | 
| - LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("glTexStorage3D"); | 
| - glTexStorage3D(target, levels, internal_format, width, height, depth); | 
| - GLenum error = LOCAL_PEEK_GL_ERROR("glTexStorage3D"); | 
| - if (error == GL_NO_ERROR) { | 
| + if (feature_info_->gl_version_info().IsLowerThanGL(4, 2) && | 
| + !features().ext_texture_storage) { | 
| + // Emulate TexStorage with TexImage or CompressedTexImage. | 
| + Buffer* bound_buffer = buffer_manager()->GetBufferInfoForTarget( | 
| + &state_, GL_PIXEL_UNPACK_BUFFER); | 
| + if (bound_buffer) { | 
| + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); | 
| + } | 
| + | 
| + scoped_ptr<char[]> zero_data; | 
| + if (is_compressed_format) { | 
| + zero_data.reset(new char[level_size[0]]); | 
| + memset(zero_data.get(), 0, level_size[0]); | 
| + } | 
| + | 
| GLsizei level_width = width; | 
| GLsizei level_height = height; | 
| GLsizei level_depth = depth; | 
| + for (int ii = 0; ii < levels; ++ii) { | 
| + if (dimension == ContextState::k2D) { | 
| + if (target == GL_TEXTURE_CUBE_MAP) { | 
| + for (int jj = 0; jj < 6; ++jj) { | 
| + GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X + jj; | 
| + if (is_compressed_format) { | 
| + glCompressedTexImage2D(face, ii, internal_format, | 
| + level_width, level_height, 0, | 
| + level_size[ii], zero_data.get()); | 
| + } else { | 
| + glTexImage2D(face, ii, internal_format, level_width, level_height, | 
| + 0, format, type, nullptr); | 
| + } | 
| + } | 
| + } else { | 
| + if (is_compressed_format) { | 
| + glCompressedTexImage2D(target, ii, internal_format, | 
| + level_width, level_height, 0, | 
| + level_size[ii], zero_data.get()); | 
| + } else { | 
| + glTexImage2D(target, ii, internal_format, level_width, level_height, | 
| + 0, format, type, nullptr); | 
| + } | 
| + } | 
| + } else { // dimension == ContextState::k3D | 
| + if (is_compressed_format) { | 
| + DCHECK(target != GL_TEXTURE_3D); | 
| + glCompressedTexImage3D(target, ii, internal_format, | 
| + level_width, level_height, level_depth, 0, | 
| + level_size[ii], zero_data.get()); | 
| + } else { | 
| + glTexImage3D(target, ii, internal_format, width, height, depth, | 
| + 0, format, type, nullptr); | 
| + } | 
| + } | 
| + level_width = std::max(1, level_width >> 1); | 
| + level_height = std::max(1, level_height >> 1); | 
| + if (target == GL_TEXTURE_3D) | 
| + level_depth = std::max(1, level_depth >> 1); | 
| + } // end of for-loop | 
| + if (bound_buffer) { | 
| + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, bound_buffer->service_id()); | 
| + } | 
| + } else { | 
| + if (dimension == ContextState::k2D) | 
| + glTexStorage2DEXT(target, levels, internal_format, width, height); | 
| + else | 
| + glTexStorage3D(target, levels, internal_format, width, height, depth); | 
| + } | 
| - GLenum cur_format = feature_info_->IsES3Enabled() ? | 
| - internal_format : format; | 
| + { | 
| + GLsizei level_width = width; | 
| + GLsizei level_height = height; | 
| + GLsizei level_depth = depth; | 
| + GLenum adjusted_format = | 
| + feature_info_->IsES3Enabled() ? internal_format : format; | 
| for (int ii = 0; ii < levels; ++ii) { | 
| - texture_manager()->SetLevelInfo(texture_ref, target, ii, cur_format, | 
| - level_width, level_height, level_depth, 0, | 
| - format, type, gfx::Rect()); | 
| + if (target == GL_TEXTURE_CUBE_MAP) { | 
| + for (int jj = 0; jj < 6; ++jj) { | 
| + GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X + jj; | 
| + texture_manager()->SetLevelInfo(texture_ref, face, ii, | 
| + adjusted_format, | 
| + level_width, level_height, 1, | 
| + 0, format, type, gfx::Rect()); | 
| + } | 
| + } else { | 
| + texture_manager()->SetLevelInfo(texture_ref, target, ii, | 
| + adjusted_format, | 
| + level_width, level_height, level_depth, | 
| + 0, format, type, gfx::Rect()); | 
| + } | 
| level_width = std::max(1, level_width >> 1); | 
| level_height = std::max(1, level_height >> 1); | 
| if (target == GL_TEXTURE_3D) | 
| @@ -14502,6 +14546,31 @@ void GLES2DecoderImpl::DoTexStorage3D( | 
| } | 
| } | 
| +void GLES2DecoderImpl::DoTexStorage2DEXT( | 
| + GLenum target, | 
| + GLint levels, | 
| + GLenum internal_format, | 
| + GLsizei width, | 
| + GLsizei height) { | 
| + TRACE_EVENT2("gpu", "GLES2DecoderImpl::DoTexStorage2D", | 
| + "width", width, "height", height); | 
| + TexStorageImpl(target, levels, internal_format, width, height, 1, | 
| + ContextState::k2D, "glTexStorage2D"); | 
| +} | 
| + | 
| +void GLES2DecoderImpl::DoTexStorage3D( | 
| + GLenum target, | 
| + GLint levels, | 
| + GLenum internal_format, | 
| + GLsizei width, | 
| + GLsizei height, | 
| + GLsizei depth) { | 
| + TRACE_EVENT2("gpu", "GLES2DecoderImpl::DoTexStorage3D", | 
| + "widthXheight", width * height, "depth", depth); | 
| + TexStorageImpl(target, levels, internal_format, width, height, depth, | 
| + ContextState::k3D, "glTexStorage3D"); | 
| +} | 
| + | 
| error::Error GLES2DecoderImpl::HandleGenMailboxCHROMIUM( | 
| uint32_t immediate_data_size, | 
| const void* cmd_data) { |