Chromium Code Reviews| Index: gpu/command_buffer/service/texture_manager.cc |
| diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc |
| index 5f93ce4fcbfd9d3dcd798aec52e566ba3c3bf059..4094dbce91259eed7f5e81c4c79345f0ff296ae2 100644 |
| --- a/gpu/command_buffer/service/texture_manager.cc |
| +++ b/gpu/command_buffer/service/texture_manager.cc |
| @@ -263,6 +263,11 @@ class FormatTypeValidator { |
| std::set<FormatType, FormatTypeCompare> supported_combinations_; |
| }; |
| +// A 32-bit and 64-bit compatible way of converting a pointer to a GLuint. |
| +GLuint ToGLuint(const void* ptr) { |
| + return static_cast<GLuint>(reinterpret_cast<size_t>(ptr)); |
| +} |
| + |
| base::LazyInstance<const FormatTypeValidator>::Leaky g_format_type_validator = |
| LAZY_INSTANCE_INITIALIZER; |
| @@ -2114,6 +2119,39 @@ bool TextureManager::ValidateTexImage( |
| return false; |
| } |
| + Buffer* buffer = state->bound_pixel_unpack_buffer.get(); |
| + if (buffer) { |
| + if (buffer->GetMappedRange()) { |
| + ERRORSTATE_SET_GL_ERROR( |
| + error_state, GL_INVALID_OPERATION, function_name, |
| + "pixel unpack buffer should not be mapped to client memory"); |
| + return error::kNoError; |
| + } |
| + base::CheckedNumeric<uint32_t> size = args.pixels_size; |
| + size += ToGLuint(args.pixels); |
| + if (!size.IsValid()) { |
| + ERRORSTATE_SET_GL_ERROR( |
| + error_state, GL_INVALID_VALUE, function_name, |
| + "size + offset overflow"); |
| + return error::kNoError; |
| + } |
| + uint32_t buffer_size = static_cast<uint32_t>(buffer->size()); |
| + if (buffer_size < size.ValueOrDefault(0)) { |
| + ERRORSTATE_SET_GL_ERROR( |
| + error_state, GL_INVALID_OPERATION, function_name, |
| + "pixel unpack buffer is not large enough"); |
| + return error::kNoError; |
| + } |
| + size_t type_size = GLES2Util::GetGLTypeSizeForTextures(args.type); |
| + DCHECK_LT(0u, type_size); |
| + if (buffer_size % type_size != 0) { |
|
piman
2016/03/08 01:56:50
Why this check? The buffer size doesn't matter, as
Zhenyao Mo
2016/03/09 18:41:05
See ES Spec 3.0.4 page 113, under $3.7 -> Unpackin
piman
2016/03/09 18:52:05
I still don't get it. The 2 requirements are:
1- t
|
| + ERRORSTATE_SET_GL_ERROR( |
| + error_state, GL_INVALID_OPERATION, function_name, |
| + "buffer size is not evenly divisible by elements"); |
| + return error::kNoError; |
| + } |
| + } |
| + |
| if (!memory_type_tracker_->EnsureGPUMemoryAvailable(args.pixels_size)) { |
| ERRORSTATE_SET_GL_ERROR(error_state, GL_OUT_OF_MEMORY, function_name, |
| "out of memory"); |
| @@ -2178,13 +2216,13 @@ void TextureManager::ValidateAndDoTexImage( |
| for (GLenum face : undefined_faces) { |
| new_args.target = face; |
| new_args.pixels = zero.get(); |
| - DoTexImage(texture_state, state->GetErrorState(), framebuffer_state, |
| + DoTexImage(texture_state, state, framebuffer_state, |
| function_name, texture_ref, new_args); |
| texture->MarkLevelAsInternalWorkaround(face, args.level); |
| } |
| } |
| - DoTexImage(texture_state, state->GetErrorState(), framebuffer_state, |
| + DoTexImage(texture_state, state, framebuffer_state, |
| function_name, texture_ref, args); |
| } |
| @@ -2203,21 +2241,7 @@ bool TextureManager::ValidateTexSubImage(ContextState* state, |
| args.target, "target"); |
| return false; |
| } |
| - if (args.width < 0) { |
| - ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_VALUE, function_name, |
| - "width < 0"); |
| - return false; |
| - } |
| - if (args.height < 0) { |
| - ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_VALUE, function_name, |
| - "height < 0"); |
| - return false; |
| - } |
| - if (args.depth < 0) { |
| - ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_VALUE, function_name, |
| - "depth < 0"); |
| - return false; |
| - } |
| + DCHECK(args.width >= 0 && args.height >= 0 && args.depth >= 0); |
| TextureRef* local_texture_ref = GetTextureInfoForTarget(state, args.target); |
| if (!local_texture_ref) { |
| ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_OPERATION, function_name, |
| @@ -2259,7 +2283,39 @@ bool TextureManager::ValidateTexSubImage(ContextState* state, |
| "can not supply data for depth or stencil textures"); |
| return false; |
| } |
| - DCHECK(args.pixels); |
| + |
| + Buffer* buffer = state->bound_pixel_unpack_buffer.get(); |
| + if (buffer) { |
| + if (buffer->GetMappedRange()) { |
| + ERRORSTATE_SET_GL_ERROR( |
| + error_state, GL_INVALID_OPERATION, function_name, |
| + "pixel unpack buffer should not be mapped to client memory"); |
| + return error::kNoError; |
| + } |
| + base::CheckedNumeric<uint32_t> size = args.pixels_size; |
| + size += ToGLuint(args.pixels); |
| + if (!size.IsValid()) { |
| + ERRORSTATE_SET_GL_ERROR( |
| + error_state, GL_INVALID_VALUE, function_name, |
| + "size + offset overflow"); |
| + return error::kNoError; |
| + } |
| + uint32_t buffer_size = static_cast<uint32_t>(buffer->size()); |
| + if (buffer_size < size.ValueOrDefault(0)) { |
| + ERRORSTATE_SET_GL_ERROR( |
| + error_state, GL_INVALID_OPERATION, function_name, |
| + "pixel unpack buffer is not large enough"); |
| + return error::kNoError; |
| + } |
| + size_t type_size = GLES2Util::GetGLTypeSizeForTextures(args.type); |
| + DCHECK_LT(0u, type_size); |
| + if (buffer_size % type_size != 0) { |
|
piman
2016/03/08 01:56:50
Same here
Zhenyao Mo
2016/03/09 18:41:05
Same answer. It is specified in a difference plac
|
| + ERRORSTATE_SET_GL_ERROR( |
| + error_state, GL_INVALID_OPERATION, function_name, |
| + "buffer size is not evenly divisible by elements"); |
| + return error::kNoError; |
| + } |
| + } |
| *texture_ref = local_texture_ref; |
| return true; |
| } |
| @@ -2365,11 +2421,12 @@ GLenum TextureManager::AdjustTexFormat(GLenum format) const { |
| void TextureManager::DoTexImage( |
| DecoderTextureState* texture_state, |
| - ErrorState* error_state, |
| + ContextState* state, |
| DecoderFramebufferState* framebuffer_state, |
| const char* function_name, |
| TextureRef* texture_ref, |
| const DoTexImageArguments& args) { |
| + ErrorState* error_state = state->GetErrorState(); |
| Texture* texture = texture_ref->texture(); |
| GLsizei tex_width = 0; |
| GLsizei tex_height = 0; |
| @@ -2385,7 +2442,10 @@ void TextureManager::DoTexImage( |
| args.target, args.level, &tex_type, &tex_internal_format) && |
| args.type == tex_type && args.internal_format == tex_internal_format; |
| - if (level_is_same && !args.pixels) { |
| + bool unpack_buffer_bound = |
| + (state->bound_pixel_unpack_buffer.get() != nullptr); |
| + |
| + if (level_is_same && !args.pixels && !unpack_buffer_bound) { |
| // Just set the level texture but mark the texture as uncleared. |
| SetLevelInfo( |
| texture_ref, args.target, args.level, args.internal_format, args.width, |
| @@ -2400,7 +2460,7 @@ void TextureManager::DoTexImage( |
| } |
| if (texture_state->texsubimage_faster_than_teximage && |
| - level_is_same && args.pixels) { |
| + level_is_same && args.pixels && !unpack_buffer_bound) { |
| { |
| ScopedTextureUploadTimer timer(texture_state); |
| if (args.command_type == DoTexImageArguments::kTexImage3D) { |
| @@ -2441,7 +2501,7 @@ void TextureManager::DoTexImage( |
| GetAllGLErrors()); |
| } |
| if (error == GL_NO_ERROR) { |
| - bool set_as_cleared = (args.pixels != nullptr); |
| + bool set_as_cleared = (args.pixels != nullptr || unpack_buffer_bound); |
| SetLevelInfo( |
| texture_ref, args.target, args.level, args.internal_format, args.width, |
| args.height, args.depth, args.border, args.format, args.type, |