| 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 0ecf45b82462e5ed80a69341a0534d238bb53053..f8583e9ac73c8aced220bd12a25a357bf0426f3e 100644
|
| --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
|
| +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
|
| @@ -189,6 +189,33 @@
|
|
|
| GLfloat v[4];
|
| };
|
| +
|
| +// Returns the union of |rect1| and |rect2| if one of the rectangles is empty,
|
| +// contains the other rectangle or shares an edge with the other rectangle.
|
| +bool 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;
|
| +}
|
|
|
| GLenum ExtractFormatFromStorageFormat(GLenum internalformat) {
|
| switch (internalformat) {
|
| @@ -11066,9 +11093,9 @@
|
| if (xoffset != 0 || yoffset != 0 || width != size.width() ||
|
| height != size.height()) {
|
| gfx::Rect cleared_rect;
|
| - if (TextureManager::CombineAdjacentRects(
|
| - texture->GetLevelClearedRect(target, level),
|
| - gfx::Rect(xoffset, yoffset, width, height), &cleared_rect)) {
|
| + if (CombineAdjacentRects(texture->GetLevelClearedRect(target, level),
|
| + gfx::Rect(xoffset, yoffset, width, height),
|
| + &cleared_rect)) {
|
| DCHECK_GE(cleared_rect.size().GetArea(),
|
| texture->GetLevelClearedRect(target, level).size().GetArea());
|
| texture_manager()->SetLevelClearedRect(texture_ref, target, level,
|
| @@ -11120,6 +11147,149 @@
|
| // This may be a slow command. Exit command processing to allow for
|
| // context preemption and GPU watchdog checks.
|
| ExitCommandProcessingEarly();
|
| +}
|
| +
|
| +bool GLES2DecoderImpl::ValidateTexSubImage2D(
|
| + error::Error* error,
|
| + const char* function_name,
|
| + GLenum target,
|
| + GLint level,
|
| + GLint xoffset,
|
| + GLint yoffset,
|
| + GLsizei width,
|
| + GLsizei height,
|
| + GLenum format,
|
| + GLenum type,
|
| + const void * data) {
|
| + (*error) = error::kNoError;
|
| + if (!validators_->texture_target.IsValid(target)) {
|
| + LOCAL_SET_GL_ERROR_INVALID_ENUM(function_name, target, "target");
|
| + return false;
|
| + }
|
| + if (width < 0) {
|
| + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, function_name, "width < 0");
|
| + return false;
|
| + }
|
| + if (height < 0) {
|
| + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, function_name, "height < 0");
|
| + return false;
|
| + }
|
| + TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget(
|
| + &state_, target);
|
| + if (!texture_ref) {
|
| + LOCAL_SET_GL_ERROR(
|
| + GL_INVALID_OPERATION,
|
| + function_name, "unknown texture for target");
|
| + return false;
|
| + }
|
| + Texture* texture = texture_ref->texture();
|
| + GLenum current_type = 0;
|
| + GLenum internal_format = 0;
|
| + if (!texture->GetLevelType(target, level, ¤t_type, &internal_format)) {
|
| + LOCAL_SET_GL_ERROR(
|
| + GL_INVALID_OPERATION, function_name, "level does not exist.");
|
| + return false;
|
| + }
|
| + if (!texture_manager()->ValidateTextureParameters(state_.GetErrorState(),
|
| + function_name, format, type, internal_format, level)) {
|
| + return false;
|
| + }
|
| + if (type != current_type && !feature_info_->IsES3Enabled()) {
|
| + LOCAL_SET_GL_ERROR(
|
| + GL_INVALID_OPERATION,
|
| + function_name, "type does not match type of texture.");
|
| + return false;
|
| + }
|
| + if (!texture->ValidForTexture(
|
| + target, level, xoffset, yoffset, 0, width, height, 1)) {
|
| + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, function_name, "bad dimensions.");
|
| + return false;
|
| + }
|
| + if ((GLES2Util::GetChannelsForFormat(format) &
|
| + (GLES2Util::kDepth | GLES2Util::kStencil)) != 0
|
| + && !feature_info_->IsES3Enabled()) {
|
| + LOCAL_SET_GL_ERROR(
|
| + GL_INVALID_OPERATION,
|
| + function_name, "can not supply data for depth or stencil textures");
|
| + return false;
|
| + }
|
| + if (data == NULL) {
|
| + (*error) = error::kOutOfBounds;
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +error::Error GLES2DecoderImpl::DoTexSubImage2D(
|
| + GLenum target,
|
| + GLint level,
|
| + GLint xoffset,
|
| + GLint yoffset,
|
| + GLsizei width,
|
| + GLsizei height,
|
| + GLenum format,
|
| + GLenum type,
|
| + const void * data) {
|
| + error::Error error = error::kNoError;
|
| + if (!ValidateTexSubImage2D(&error, "glTexSubImage2D", target, level,
|
| + xoffset, yoffset, width, height, format, type, data)) {
|
| + return error;
|
| + }
|
| + TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget(
|
| + &state_, target);
|
| + Texture* texture = texture_ref->texture();
|
| + GLsizei tex_width = 0;
|
| + GLsizei tex_height = 0;
|
| + bool ok = texture->GetLevelSize(
|
| + target, level, &tex_width, &tex_height, nullptr);
|
| + DCHECK(ok);
|
| + if (xoffset != 0 || yoffset != 0 ||
|
| + width != tex_width || height != tex_height) {
|
| + gfx::Rect cleared_rect;
|
| + if (CombineAdjacentRects(texture->GetLevelClearedRect(target, level),
|
| + gfx::Rect(xoffset, yoffset, width, height),
|
| + &cleared_rect)) {
|
| + DCHECK_GE(cleared_rect.size().GetArea(),
|
| + texture->GetLevelClearedRect(target, level).size().GetArea());
|
| + texture_manager()->SetLevelClearedRect(texture_ref, target, level,
|
| + cleared_rect);
|
| + } else {
|
| + // Otherwise clear part of texture level that is not already cleared.
|
| + if (!texture_manager()->ClearTextureLevel(this, texture_ref, target,
|
| + level)) {
|
| + LOCAL_SET_GL_ERROR(GL_OUT_OF_MEMORY, "glTexSubImage2D",
|
| + "dimensions too big");
|
| + return error::kNoError;
|
| + }
|
| + }
|
| + ScopedTextureUploadTimer timer(&texture_state_);
|
| + glTexSubImage2D(
|
| + target, level, xoffset, yoffset, width, height, format, type, data);
|
| + return error::kNoError;
|
| + }
|
| +
|
| + if (!texture_state_.texsubimage_faster_than_teximage &&
|
| + !texture->IsImmutable() &&
|
| + !texture->HasImages()) {
|
| + ScopedTextureUploadTimer timer(&texture_state_);
|
| + GLenum internal_format;
|
| + GLenum tex_type;
|
| + texture->GetLevelType(target, 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(
|
| + target, level, internal_format, width, height, 0, format, type, data);
|
| + } else {
|
| + ScopedTextureUploadTimer timer(&texture_state_);
|
| + glTexSubImage2D(
|
| + target, level, xoffset, yoffset, width, height, format, type, data);
|
| + }
|
| + texture_manager()->SetLevelCleared(texture_ref, target, level, true);
|
| +
|
| + // This may be a slow command. Exit command processing to allow for
|
| + // context preemption and GPU watchdog checks.
|
| + ExitCommandProcessingEarly();
|
| + return error::kNoError;
|
| }
|
|
|
| error::Error GLES2DecoderImpl::HandleTexSubImage2D(uint32 immediate_data_size,
|
| @@ -11146,23 +11316,10 @@
|
| NULL, NULL)) {
|
| return error::kOutOfBounds;
|
| }
|
| -
|
| const void* pixels = GetSharedMemoryAs<const void*>(
|
| c.pixels_shm_id, c.pixels_shm_offset, data_size);
|
| - if (!pixels)
|
| - return error::kOutOfBounds;
|
| -
|
| - TextureManager::DoTexSubImageArguments args = {
|
| - target, level, xoffset, yoffset, width,
|
| - height, format, type, pixels, data_size};
|
| - texture_manager()->ValidateAndDoTexSubImage(this, &texture_state_, &state_,
|
| - &framebuffer_state_,
|
| - "glTexSubImage2D", args);
|
| -
|
| - // This may be a slow command. Exit command processing to allow for
|
| - // context preemption and GPU watchdog checks.
|
| - ExitCommandProcessingEarly();
|
| - return error::kNoError;
|
| + return DoTexSubImage2D(
|
| + target, level, xoffset, yoffset, width, height, format, type, pixels);
|
| }
|
|
|
| error::Error GLES2DecoderImpl::DoTexSubImage3D(
|
| @@ -13100,9 +13257,9 @@
|
| if (xoffset != 0 || yoffset != 0 || width != dest_width ||
|
| height != dest_height) {
|
| gfx::Rect cleared_rect;
|
| - if (TextureManager::CombineAdjacentRects(
|
| - dest_texture->GetLevelClearedRect(target, 0),
|
| - gfx::Rect(xoffset, yoffset, width, height), &cleared_rect)) {
|
| + if (CombineAdjacentRects(dest_texture->GetLevelClearedRect(target, 0),
|
| + gfx::Rect(xoffset, yoffset, width, height),
|
| + &cleared_rect)) {
|
| DCHECK_GE(cleared_rect.size().GetArea(),
|
| dest_texture->GetLevelClearedRect(target, 0).size().GetArea());
|
| texture_manager()->SetLevelClearedRect(dest_texture_ref, target, 0,
|
| @@ -13438,9 +13595,9 @@
|
| if (xoffset != 0 || yoffset != 0 || width != dest_width ||
|
| height != dest_height) {
|
| gfx::Rect cleared_rect;
|
| - if (TextureManager::CombineAdjacentRects(
|
| - dest_texture->GetLevelClearedRect(target, 0),
|
| - gfx::Rect(xoffset, yoffset, width, height), &cleared_rect)) {
|
| + if (CombineAdjacentRects(dest_texture->GetLevelClearedRect(target, 0),
|
| + gfx::Rect(xoffset, yoffset, width, height),
|
| + &cleared_rect)) {
|
| DCHECK_GE(cleared_rect.size().GetArea(),
|
| dest_texture->GetLevelClearedRect(target, 0).size().GetArea());
|
| texture_manager()->SetLevelClearedRect(dest_texture_ref, target, 0,
|
|
|