| 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 4f856d6ae234b326ac0154ed9c650aa2e57a8efb..bd93329f00e14d9c7888a0cca4695b26229ef1e0 100644
|
| --- a/gpu/command_buffer/service/texture_manager.cc
|
| +++ b/gpu/command_buffer/service/texture_manager.cc
|
| @@ -22,6 +22,7 @@
|
| #include "gpu/command_buffer/service/mailbox_manager.h"
|
| #include "gpu/command_buffer/service/memory_tracking.h"
|
| #include "ui/gl/gl_implementation.h"
|
| +#include "ui/gl/gl_version_info.h"
|
| #include "ui/gl/trace_util.h"
|
|
|
| namespace gpu {
|
| @@ -2002,6 +2003,138 @@ void TextureManager::ValidateAndDoTexImage(
|
| function_name, texture_ref, args);
|
| }
|
|
|
| +bool TextureManager::ValidateTexSubImage(ContextState* state,
|
| + const char* function_name,
|
| + const DoTexSubImageArguments& args,
|
| + TextureRef** texture_ref) {
|
| + ErrorState* error_state = state->GetErrorState();
|
| + const Validators* validators = feature_info_->validators();
|
| +
|
| + if (!validators->texture_target.IsValid(args.target)) {
|
| + ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(error_state, function_name,
|
| + 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;
|
| + }
|
| + TextureRef* local_texture_ref = GetTextureInfoForTarget(state, args.target);
|
| + if (!local_texture_ref) {
|
| + ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_OPERATION, function_name,
|
| + "unknown texture for target");
|
| + return false;
|
| + }
|
| + Texture* texture = local_texture_ref->texture();
|
| + GLenum current_type = 0;
|
| + GLenum internal_format = 0;
|
| + if (!texture->GetLevelType(args.target, args.level, ¤t_type,
|
| + &internal_format)) {
|
| + ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_OPERATION, function_name,
|
| + "level does not exist.");
|
| + return false;
|
| + }
|
| + if (!ValidateTextureParameters(error_state, function_name, args.format,
|
| + args.type, internal_format, args.level)) {
|
| + return false;
|
| + }
|
| + if (args.type != current_type && !feature_info_->IsES3Enabled()) {
|
| + ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_OPERATION, function_name,
|
| + "type does not match type of texture.");
|
| + return false;
|
| + }
|
| + if (!texture->ValidForTexture(args.target, args.level, args.xoffset,
|
| + args.yoffset, 0, args.width, args.height, 1)) {
|
| + ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_VALUE, function_name,
|
| + "bad dimensions.");
|
| + return false;
|
| + }
|
| + if ((GLES2Util::GetChannelsForFormat(args.format) &
|
| + (GLES2Util::kDepth | GLES2Util::kStencil)) != 0 &&
|
| + !feature_info_->IsES3Enabled()) {
|
| + ERRORSTATE_SET_GL_ERROR(
|
| + error_state, GL_INVALID_OPERATION, function_name,
|
| + "can not supply data for depth or stencil textures");
|
| + return false;
|
| + }
|
| + DCHECK(args.pixels);
|
| + *texture_ref = local_texture_ref;
|
| + return true;
|
| +}
|
| +
|
| +void TextureManager::ValidateAndDoTexSubImage(
|
| + GLES2Decoder* decoder,
|
| + DecoderTextureState* texture_state,
|
| + ContextState* state,
|
| + DecoderFramebufferState* framebuffer_state,
|
| + const char* function_name,
|
| + const DoTexSubImageArguments& args) {
|
| + ErrorState* error_state = state->GetErrorState();
|
| + TextureRef* texture_ref;
|
| + if (!ValidateTexSubImage(state, function_name, args, &texture_ref)) {
|
| + return;
|
| + }
|
| +
|
| + Texture* texture = texture_ref->texture();
|
| + GLsizei tex_width = 0;
|
| + GLsizei tex_height = 0;
|
| + bool ok = texture->GetLevelSize(args.target, args.level, &tex_width,
|
| + &tex_height, nullptr);
|
| + DCHECK(ok);
|
| + if (args.xoffset != 0 || args.yoffset != 0 || args.width != tex_width ||
|
| + args.height != tex_height) {
|
| + gfx::Rect cleared_rect;
|
| + if (CombineAdjacentRects(
|
| + texture->GetLevelClearedRect(args.target, args.level),
|
| + gfx::Rect(args.xoffset, args.yoffset, args.width, args.height),
|
| + &cleared_rect)) {
|
| + DCHECK_GE(cleared_rect.size().GetArea(),
|
| + texture->GetLevelClearedRect(args.target, args.level)
|
| + .size()
|
| + .GetArea());
|
| + SetLevelClearedRect(texture_ref, args.target, args.level, cleared_rect);
|
| + } else {
|
| + // Otherwise clear part of texture level that is not already cleared.
|
| + if (!ClearTextureLevel(decoder, texture_ref, args.target, args.level)) {
|
| + ERRORSTATE_SET_GL_ERROR(error_state, GL_OUT_OF_MEMORY,
|
| + "glTexSubImage2D", "dimensions too big");
|
| + return;
|
| + }
|
| + }
|
| + ScopedTextureUploadTimer timer(texture_state);
|
| + glTexSubImage2D(args.target, args.level, args.xoffset, args.yoffset,
|
| + args.width, args.height, AdjustTexFormat(args.format),
|
| + args.type, args.pixels);
|
| + return;
|
| + }
|
| +
|
| + if (!texture_state->texsubimage_faster_than_teximage &&
|
| + !texture->IsImmutable() && !texture->HasImages()) {
|
| + ScopedTextureUploadTimer timer(texture_state);
|
| + GLenum internal_format;
|
| + GLenum tex_type;
|
| + texture->GetLevelType(args.target, args.level, &tex_type, &internal_format);
|
| + // NOTE: In OpenGL ES 2.0 border is always zero. If that changes we'll need
|
| + // to look it up.
|
| + glTexImage2D(args.target, args.level, internal_format, args.width,
|
| + args.height, 0, AdjustTexFormat(args.format), args.type,
|
| + args.pixels);
|
| + } else {
|
| + ScopedTextureUploadTimer timer(texture_state);
|
| + glTexSubImage2D(args.target, args.level, args.xoffset, args.yoffset,
|
| + args.width, args.height, AdjustTexFormat(args.format),
|
| + args.type, args.pixels);
|
| + }
|
| + SetLevelCleared(texture_ref, args.target, args.level, true);
|
| + return;
|
| +}
|
| +
|
| GLenum TextureManager::AdjustTexFormat(GLenum format) const {
|
| // TODO(bajones): GLES 3 allows for internal format and format to differ.
|
| // This logic may need to change as a result.
|
| @@ -2089,6 +2222,31 @@ void TextureManager::DoTexImage(
|
| }
|
| }
|
|
|
| +bool TextureManager::CombineAdjacentRects(const gfx::Rect& rect1,
|
| + const gfx::Rect& rect2,
|
| + gfx::Rect* result) {
|
| + // Return |rect2| if |rect1| is empty or |rect2| contains |rect1|.
|
| + if (rect1.IsEmpty() || rect2.Contains(rect1)) {
|
| + *result = rect2;
|
| + return true;
|
| + }
|
| +
|
| + // Return |rect1| if |rect2| is empty or |rect1| contains |rect2|.
|
| + if (rect2.IsEmpty() || rect1.Contains(rect2)) {
|
| + *result = rect1;
|
| + return true;
|
| + }
|
| +
|
| + // Return the union of |rect1| and |rect2| if they share an edge.
|
| + if (rect1.SharesEdgeWith(rect2)) {
|
| + *result = gfx::UnionRects(rect1, rect2);
|
| + return true;
|
| + }
|
| +
|
| + // Return false if it's not possible to combine |rect1| and |rect2|.
|
| + return false;
|
| +}
|
| +
|
| ScopedTextureUploadTimer::ScopedTextureUploadTimer(
|
| DecoderTextureState* texture_state)
|
| : texture_state_(texture_state),
|
|
|