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 6df7f6a2f816a89bb6e37149101e0a60c27a2da4..e00dc0516165bf907fc00ad7ba7c47abe0dacf4a 100644 |
| --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc |
| +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc |
| @@ -64,6 +64,7 @@ |
| #include "gpu/command_buffer/service/transform_feedback_manager.h" |
| #include "gpu/command_buffer/service/vertex_array_manager.h" |
| #include "gpu/command_buffer/service/vertex_attrib_manager.h" |
| +#include "third_party/angle/src/image_util/loadimage.h" |
| #include "third_party/smhasher/src/City.h" |
| #include "ui/gfx/buffer_types.h" |
| #include "ui/gfx/geometry/point.h" |
| @@ -936,30 +937,28 @@ class GLES2DecoderImpl : public GLES2Decoder, public ErrorStateClient { |
| const void* data); |
| // Wrapper for CompressedTexSubImage2D. |
| - void DoCompressedTexSubImage2D( |
| - GLenum target, |
| - GLint level, |
| - GLint xoffset, |
| - GLint yoffset, |
| - GLsizei width, |
| - GLsizei height, |
| - GLenum format, |
| - GLsizei imageSize, |
| - const void* data); |
| + error::Error DoCompressedTexSubImage2D(GLenum target, |
| + GLint level, |
| + GLint xoffset, |
| + GLint yoffset, |
| + GLsizei width, |
| + GLsizei height, |
| + GLenum format, |
| + GLsizei imageSize, |
| + const void* data); |
| // Wrapper for CompressedTexSubImage3D. |
| - void DoCompressedTexSubImage3D( |
| - GLenum target, |
| - GLint level, |
| - GLint xoffset, |
| - GLint yoffset, |
| - GLint zoffset, |
| - GLsizei width, |
| - GLsizei height, |
| - GLsizei depth, |
| - GLenum format, |
| - GLsizei image_size, |
| - const void* data); |
| + error::Error DoCompressedTexSubImage3D(GLenum target, |
| + GLint level, |
| + GLint xoffset, |
| + GLint yoffset, |
| + GLint zoffset, |
| + GLsizei width, |
| + GLsizei height, |
| + GLsizei depth, |
| + GLenum format, |
| + GLsizei image_size, |
| + const void* data); |
| // Validate if |format| is valid for CopyTex{Sub}Image functions. |
| // If not, generate a GL error and return false. |
| @@ -1900,9 +1899,13 @@ class GLES2DecoderImpl : public GLES2Decoder, public ErrorStateClient { |
| bool ValidateCompressedTexDimensions( |
| const char* function_name, GLenum target, GLint level, |
| GLsizei width, GLsizei height, GLsizei depth, GLenum format); |
| - bool ValidateCompressedTexFuncData( |
| - const char* function_name, GLsizei width, GLsizei height, GLsizei depth, |
| - GLenum format, GLsizei size); |
| + bool ValidateCompressedTexFuncData(const char* function_name, |
| + GLsizei width, |
| + GLsizei height, |
| + GLsizei depth, |
| + GLenum format, |
| + GLsizei size, |
| + const GLvoid* data); |
| bool ValidateCompressedTexSubDimensions( |
| const char* function_name, |
| GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, |
| @@ -11482,6 +11485,141 @@ const ASTCBlockArray kASTCBlockArray[] = { |
| {12, 10}, |
| {12, 12}}; |
| +bool CheckETCFormatSupport(const FeatureInfo& featureInfo) { |
| + const gl::GLVersionInfo& versionInfo = featureInfo.gl_version_info(); |
| + return versionInfo.IsAtLeastGL(4, 3) || versionInfo.IsAtLeastGLES(3, 0) || |
| + featureInfo.feature_flags().arb_es3_compatibility; |
| +} |
| + |
| +using CompressedFormatSupportCheck = bool (*)(const FeatureInfo&); |
| +using CompressedFormatDecompressionFunction = void (*)(size_t width, |
| + size_t height, |
| + size_t depth, |
| + const uint8_t* input, |
| + size_t inputRowPitch, |
| + size_t inputDepthPitch, |
| + uint8_t* output, |
| + size_t outputRowPitch, |
| + size_t outputDepthPitch); |
| + |
| +struct CompressedFormatInfo { |
| + GLenum format; |
| + uint32_t block_size; |
| + uint32_t bytes_per_block; |
| + CompressedFormatSupportCheck support_check; |
| + CompressedFormatDecompressionFunction decompression_function; |
| + GLenum decompressed_internal_format; |
| + GLenum decompressed_format; |
| + GLenum decompressed_type; |
| +}; |
| + |
| +const CompressedFormatInfo kCompressedFormatInfoArray[] = { |
| + { |
| + GL_COMPRESSED_R11_EAC, 4, 8, CheckETCFormatSupport, |
| + angle::LoadEACR11ToR8, GL_R8, GL_RED, GL_UNSIGNED_BYTE, |
| + }, |
| + { |
| + GL_COMPRESSED_SIGNED_R11_EAC, 4, 8, CheckETCFormatSupport, |
| + angle::LoadEACR11SToR8, GL_R8_SNORM, GL_RED, GL_BYTE, |
| + }, |
| + { |
| + GL_COMPRESSED_RG11_EAC, 4, 16, CheckETCFormatSupport, |
| + angle::LoadEACRG11ToRG8, GL_RG8, GL_RG, GL_UNSIGNED_BYTE, |
| + }, |
| + { |
| + GL_COMPRESSED_SIGNED_RG11_EAC, 4, 16, CheckETCFormatSupport, |
| + angle::LoadEACRG11SToRG8, GL_RG8_SNORM, GL_RG, GL_BYTE, |
| + }, |
| + { |
| + GL_COMPRESSED_RGB8_ETC2, 4, 8, CheckETCFormatSupport, |
| + angle::LoadETC2RGB8ToRGBA8, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, |
| + }, |
| + { |
| + GL_COMPRESSED_SRGB8_ETC2, 4, 8, CheckETCFormatSupport, |
| + angle::LoadETC2SRGB8ToRGBA8, GL_SRGB8_ALPHA8, GL_SRGB_ALPHA, |
| + GL_UNSIGNED_BYTE, |
| + }, |
| + { |
| + GL_COMPRESSED_RGBA8_ETC2_EAC, 4, 16, CheckETCFormatSupport, |
| + angle::LoadETC2RGBA8ToRGBA8, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, |
| + }, |
| + { |
| + GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, 4, 8, |
| + CheckETCFormatSupport, angle::LoadETC2RGB8A1ToRGBA8, GL_RGBA8, GL_RGBA, |
| + GL_UNSIGNED_BYTE, |
| + }, |
| + { |
| + GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, 4, 16, CheckETCFormatSupport, |
| + angle::LoadETC2SRGBA8ToSRGBA8, GL_SRGB8_ALPHA8, GL_SRGB_ALPHA, |
| + GL_UNSIGNED_BYTE, |
| + }, |
| + { |
| + GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, 4, 8, |
| + CheckETCFormatSupport, angle::LoadETC2SRGB8A1ToRGBA8, GL_SRGB8_ALPHA8, |
| + GL_SRGB_ALPHA, GL_UNSIGNED_BYTE, |
| + }, |
| +}; |
| + |
| +const CompressedFormatInfo* GetCompressedFormatInfo(GLenum format) { |
| + for (size_t i = 0; i < arraysize(kCompressedFormatInfoArray); i++) { |
| + if (kCompressedFormatInfoArray[i].format == format) { |
| + return &kCompressedFormatInfoArray[i]; |
| + } |
| + } |
| + return nullptr; |
| +} |
| + |
| +uint32_t GetCompressedFormatRowPitch(const CompressedFormatInfo& info, |
| + uint32_t width) { |
| + uint32_t num_blocks_wide = (width + info.block_size - 1) / info.block_size; |
| + return num_blocks_wide * info.bytes_per_block; |
| +} |
| + |
| +uint32_t GetCompressedFormatDepthPitch(const CompressedFormatInfo& info, |
| + uint32_t width, |
| + uint32_t height) { |
| + uint32_t num_blocks_high = (height + info.block_size - 1) / info.block_size; |
| + return num_blocks_high * GetCompressedFormatRowPitch(info, width); |
| +} |
| + |
| +std::unique_ptr<uint8_t[]> DecompressTextureData( |
| + const ContextState& state, |
| + const CompressedFormatInfo& info, |
| + uint32_t width, |
| + uint32_t height, |
| + uint32_t depth, |
| + GLsizei image_size, |
| + const void* data) { |
| + uint32_t output_pixel_size = GLES2Util::ComputeImageGroupSize( |
| + info.decompressed_format, info.decompressed_type); |
| + std::unique_ptr<uint8_t[]> decompressed_data( |
| + new uint8_t[output_pixel_size * width * height]); |
| + |
| + // If a PBO is bound, map it to decompress the data. |
| + const void* input_data = data; |
| + if (state.bound_pixel_unpack_buffer) { |
| + input_data = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, |
| + reinterpret_cast<GLintptr>(data), image_size, |
| + GL_MAP_READ_BIT); |
| + } |
| + |
| + info.decompression_function( |
| + width, height, depth, static_cast<const uint8_t*>(input_data), |
| + GetCompressedFormatRowPitch(info, width), |
| + GetCompressedFormatDepthPitch(info, width, height), |
| + decompressed_data.get(), output_pixel_size * width, |
| + output_pixel_size * width * height); |
| + |
| + if (state.bound_pixel_unpack_buffer) { |
| + if (glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER) != GL_TRUE) { |
| + LOG(ERROR) << "glUnmapBuffer unexpectedly returned GL_FALSE"; |
| + return nullptr; |
| + } |
| + } |
| + |
| + return decompressed_data; |
| +} |
| + |
| bool IsValidDXTSize(GLint level, GLsizei size) { |
| // TODO(zmo): Linux NVIDIA driver does allow size of 1 and 2 on level 0. |
| // However, the WebGL conformance test and blink side code forbid it. |
| @@ -11623,9 +11761,13 @@ bool GLES2DecoderImpl::GetCompressedTexSizeInBytes( |
| return true; |
| } |
| -bool GLES2DecoderImpl::ValidateCompressedTexFuncData( |
| - const char* function_name, GLsizei width, GLsizei height, GLsizei depth, |
| - GLenum format, GLsizei size) { |
| +bool GLES2DecoderImpl::ValidateCompressedTexFuncData(const char* function_name, |
| + GLsizei width, |
| + GLsizei height, |
| + GLsizei depth, |
| + GLenum format, |
| + GLsizei size, |
| + const GLvoid* data) { |
| GLsizei bytes_required = 0; |
| if (!GetCompressedTexSizeInBytes( |
| function_name, width, height, depth, format, &bytes_required)) { |
| @@ -11638,6 +11780,25 @@ bool GLES2DecoderImpl::ValidateCompressedTexFuncData( |
| return false; |
| } |
| + if (state_.bound_pixel_unpack_buffer.get()) { |
| + if (state_.bound_pixel_unpack_buffer->GetMappedRange() != nullptr) { |
| + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name, |
| + "pixel unpack buffer is mapped"); |
| + return false; |
| + } |
| + |
| + base::CheckedNumeric<GLintptr> pbo_bytes_required( |
| + reinterpret_cast<GLintptr>(data)); |
| + pbo_bytes_required += bytes_required; |
| + if (!pbo_bytes_required.IsValid() || |
| + pbo_bytes_required.ValueOrDie() > |
| + state_.bound_pixel_unpack_buffer->size()) { |
| + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name, |
| + "pixel unpack buffer is not large enough"); |
| + return false; |
| + } |
| + } |
| + |
| return true; |
| } |
| @@ -11889,8 +12050,8 @@ error::Error GLES2DecoderImpl::DoCompressedTexImage2D( |
| } |
| if (!ValidateCompressedTexDimensions("glCompressedTexImage2D", target, level, |
| width, height, 1, internal_format) || |
| - !ValidateCompressedTexFuncData("glCompressedTexImage2D", width, height, |
| - 1, internal_format, image_size)) { |
| + !ValidateCompressedTexFuncData("glCompressedTexImage2D", width, height, 1, |
| + internal_format, image_size, data)) { |
| return error::kNoError; |
| } |
| @@ -11905,14 +12066,32 @@ error::Error GLES2DecoderImpl::DoCompressedTexImage2D( |
| } |
| std::unique_ptr<int8_t[]> zero; |
| - if (!data) { |
| + if (!state_.bound_pixel_unpack_buffer && !data) { |
| zero.reset(new int8_t[image_size]); |
| memset(zero.get(), 0, image_size); |
| data = zero.get(); |
| } |
| LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("glCompressedTexImage2D"); |
| - glCompressedTexImage2D( |
| - target, level, internal_format, width, height, border, image_size, data); |
| + |
| + const CompressedFormatInfo* format_info = |
| + GetCompressedFormatInfo(internal_format); |
| + if (format_info != nullptr && !format_info->support_check(*feature_info_)) { |
| + std::unique_ptr<uint8_t[]> decompressed_data = DecompressTextureData( |
| + state_, *format_info, width, height, 1, image_size, data); |
| + if (!decompressed_data) { |
| + MarkContextLost(error::kGuilty); |
| + group_->LoseContexts(error::kInnocent); |
| + return error::kLostContext; |
|
piman
2016/07/11 19:38:45
You don't really need to return kLostContext here,
Geoff Lang
2016/07/11 20:08:36
Done.
|
| + } |
| + state_.PushTextureDecompressionUnpackState(); |
| + glTexImage2D(target, level, format_info->decompressed_internal_format, |
| + width, height, border, format_info->decompressed_format, |
| + format_info->decompressed_type, decompressed_data.get()); |
| + state_.RestoreUnpackState(); |
| + } else { |
| + glCompressedTexImage2D(target, level, internal_format, width, height, |
| + border, image_size, data); |
| + } |
| GLenum error = LOCAL_PEEK_GL_ERROR("glCompressedTexImage2D"); |
| if (error == GL_NO_ERROR) { |
| texture_manager()->SetLevelInfo(texture_ref, target, level, internal_format, |
| @@ -11962,7 +12141,8 @@ error::Error GLES2DecoderImpl::DoCompressedTexImage3D( |
| if (!ValidateCompressedTexDimensions("glCompressedTexImage3D", target, level, |
| width, height, depth, internal_format) || |
| !ValidateCompressedTexFuncData("glCompressedTexImage3D", width, height, |
| - depth, internal_format, image_size)) { |
| + depth, internal_format, image_size, |
| + data)) { |
| return error::kNoError; |
| } |
| @@ -11977,14 +12157,31 @@ error::Error GLES2DecoderImpl::DoCompressedTexImage3D( |
| } |
| std::unique_ptr<int8_t[]> zero; |
| - if (!data) { |
| + if (!state_.bound_pixel_unpack_buffer && !data) { |
| zero.reset(new int8_t[image_size]); |
| memset(zero.get(), 0, image_size); |
| data = zero.get(); |
| } |
| LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("glCompressedTexImage3D"); |
| - glCompressedTexImage3D(target, level, internal_format, width, height, depth, |
| - border, image_size, data); |
| + const CompressedFormatInfo* format_info = |
| + GetCompressedFormatInfo(internal_format); |
| + if (format_info != nullptr && !format_info->support_check(*feature_info_)) { |
| + std::unique_ptr<uint8_t[]> decompressed_data = DecompressTextureData( |
| + state_, *format_info, width, height, depth, image_size, data); |
| + if (!decompressed_data) { |
| + MarkContextLost(error::kGuilty); |
| + group_->LoseContexts(error::kInnocent); |
| + return error::kLostContext; |
| + } |
| + state_.PushTextureDecompressionUnpackState(); |
| + glTexImage3D(target, level, format_info->decompressed_internal_format, |
| + width, height, depth, border, format_info->decompressed_format, |
| + format_info->decompressed_type, decompressed_data.get()); |
| + state_.RestoreUnpackState(); |
| + } else { |
| + glCompressedTexImage3D(target, level, internal_format, width, height, depth, |
| + border, image_size, data); |
| + } |
| GLenum error = LOCAL_PEEK_GL_ERROR("glCompressedTexImage3D"); |
| if (error == GL_NO_ERROR) { |
| texture_manager()->SetLevelInfo(texture_ref, target, level, internal_format, |
| @@ -11998,22 +12195,29 @@ error::Error GLES2DecoderImpl::DoCompressedTexImage3D( |
| return error::kNoError; |
| } |
| -void GLES2DecoderImpl::DoCompressedTexSubImage3D( |
| - GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, |
| - GLsizei width, GLsizei height, GLsizei depth, GLenum format, |
| - GLsizei image_size, const void* data) { |
| +error::Error GLES2DecoderImpl::DoCompressedTexSubImage3D(GLenum target, |
| + GLint level, |
| + GLint xoffset, |
| + GLint yoffset, |
| + GLint zoffset, |
| + GLsizei width, |
| + GLsizei height, |
| + GLsizei depth, |
| + GLenum format, |
| + GLsizei image_size, |
| + const void* data) { |
| if (!texture_manager()->ValidForTarget(target, level, width, height, depth)) { |
| LOCAL_SET_GL_ERROR( |
| GL_INVALID_VALUE, |
| "glCompressedTexSubImage3D", "dimensions out of range"); |
| - return; |
| + return error::kNoError; |
| } |
| TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget( |
| &state_, target); |
| if (!texture_ref) { |
| LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glCompressedTexSubImage3D", |
| "unknown texture for target"); |
| - return; |
| + return error::kNoError; |
| } |
| Texture* texture = texture_ref->texture(); |
| GLenum type = 0, internal_format = 0; |
| @@ -12022,40 +12226,56 @@ void GLES2DecoderImpl::DoCompressedTexSubImage3D( |
| "level %d does not exist", level); |
| LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glCompressedTexSubImage3D", |
| msg.c_str()); |
| - return; |
| + return error::kNoError; |
| } |
| if (internal_format != format) { |
| LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glCompressedTexSubImage3D", |
| "format does not match internal format"); |
| - return; |
| + return error::kNoError; |
| } |
| if (!texture->ValidForTexture(target, level, xoffset, yoffset, zoffset, |
| width, height, depth)) { |
| LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCompressedTexSubImage3D", |
| "bad dimensions"); |
| - return; |
| + return error::kNoError; |
| } |
| - if (!ValidateCompressedTexFuncData("glCompressedTexSubImage3D", |
| - width, height, depth, format, |
| - image_size) || |
| - !ValidateCompressedTexSubDimensions("glCompressedTexSubImage3D", |
| - target, level, xoffset, yoffset, |
| - zoffset, width, height, depth, |
| - format, texture)) { |
| - return; |
| + if (!ValidateCompressedTexFuncData("glCompressedTexSubImage3D", width, height, |
| + depth, format, image_size, data) || |
| + !ValidateCompressedTexSubDimensions( |
| + "glCompressedTexSubImage3D", target, level, xoffset, yoffset, zoffset, |
| + width, height, depth, format, texture)) { |
| + return error::kNoError; |
| } |
| // Note: There is no need to deal with texture cleared tracking here |
| // because the validation above means you can only get here if the level |
| // is already a matching compressed format and in that case |
| // CompressedTexImage3D already cleared the texture. |
| - glCompressedTexSubImage3D( |
| - target, level, xoffset, yoffset, zoffset, width, height, depth, format, |
| - image_size, data); |
| + |
| + const CompressedFormatInfo* format_info = |
| + GetCompressedFormatInfo(internal_format); |
| + if (format_info != nullptr && !format_info->support_check(*feature_info_)) { |
| + std::unique_ptr<uint8_t[]> decompressed_data = DecompressTextureData( |
| + state_, *format_info, width, height, depth, image_size, data); |
| + if (!decompressed_data) { |
| + MarkContextLost(error::kGuilty); |
| + group_->LoseContexts(error::kInnocent); |
| + return error::kLostContext; |
| + } |
| + state_.PushTextureDecompressionUnpackState(); |
| + glTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, |
| + depth, format_info->decompressed_format, |
| + format_info->decompressed_type, decompressed_data.get()); |
| + state_.RestoreUnpackState(); |
| + } else { |
| + glCompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, |
| + height, depth, format, image_size, data); |
| + } |
| // 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::HandleTexImage2D(uint32_t immediate_data_size, |
| @@ -12234,22 +12454,28 @@ error::Error GLES2DecoderImpl::HandleTexImage3D(uint32_t immediate_data_size, |
| return error::kNoError; |
| } |
| -void GLES2DecoderImpl::DoCompressedTexSubImage2D( |
| - GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, |
| - GLsizei height, GLenum format, GLsizei image_size, const void * data) { |
| +error::Error GLES2DecoderImpl::DoCompressedTexSubImage2D(GLenum target, |
| + GLint level, |
| + GLint xoffset, |
| + GLint yoffset, |
| + GLsizei width, |
| + GLsizei height, |
| + GLenum format, |
| + GLsizei image_size, |
| + const void* data) { |
| TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget( |
| &state_, target); |
| if (!texture_ref) { |
| LOCAL_SET_GL_ERROR( |
| GL_INVALID_OPERATION, |
| "glCompressedTexSubImage2D", "unknown texture for target"); |
| - return; |
| + return error::kNoError; |
| } |
| if (!texture_manager()->ValidForTarget(target, level, width, height, 1)) { |
| LOCAL_SET_GL_ERROR( |
| GL_INVALID_VALUE, |
| "glCompressedTexSubImage2D", "dimensions out of range"); |
| - return; |
| + return error::kNoError; |
| } |
| Texture* texture = texture_ref->texture(); |
| GLenum type = 0; |
| @@ -12259,27 +12485,27 @@ void GLES2DecoderImpl::DoCompressedTexSubImage2D( |
| "level %d does not exist", level); |
| LOCAL_SET_GL_ERROR( |
| GL_INVALID_OPERATION, "glCompressedTexSubImage2D", msg.c_str()); |
| - return; |
| + return error::kNoError; |
| } |
| if (internal_format != format) { |
| LOCAL_SET_GL_ERROR( |
| GL_INVALID_OPERATION, |
| "glCompressedTexSubImage2D", "format does not match internal format."); |
| - return; |
| + return error::kNoError; |
| } |
| if (!texture->ValidForTexture(target, level, xoffset, yoffset, 0, width, |
| height, 1)) { |
| LOCAL_SET_GL_ERROR( |
| GL_INVALID_VALUE, "glCompressedTexSubImage2D", "bad dimensions."); |
| - return; |
| + return error::kNoError; |
| } |
| - if (!ValidateCompressedTexFuncData("glCompressedTexSubImage2D", |
| - width, height, 1, format, image_size) || |
| - !ValidateCompressedTexSubDimensions("glCompressedTexSubImage2D", |
| - target, level, xoffset, yoffset, 0, |
| - width, height, 1, format, texture)) { |
| - return; |
| + if (!ValidateCompressedTexFuncData("glCompressedTexSubImage2D", width, height, |
| + 1, format, image_size, data) || |
| + !ValidateCompressedTexSubDimensions("glCompressedTexSubImage2D", target, |
| + level, xoffset, yoffset, 0, width, |
| + height, 1, format, texture)) { |
| + return error::kNoError; |
| } |
| if (!texture->IsLevelCleared(target, level)) { |
| @@ -12300,12 +12526,30 @@ void GLES2DecoderImpl::DoCompressedTexSubImage2D( |
| DCHECK(texture->IsLevelCleared(target, level)); |
| } |
| - glCompressedTexSubImage2D( |
| - target, level, xoffset, yoffset, width, height, format, image_size, data); |
| + const CompressedFormatInfo* format_info = |
| + GetCompressedFormatInfo(internal_format); |
| + if (format_info != nullptr && !format_info->support_check(*feature_info_)) { |
| + std::unique_ptr<uint8_t[]> decompressed_data = DecompressTextureData( |
| + state_, *format_info, width, height, 1, image_size, data); |
| + if (!decompressed_data) { |
| + MarkContextLost(error::kGuilty); |
| + group_->LoseContexts(error::kInnocent); |
| + return error::kLostContext; |
| + } |
| + state_.PushTextureDecompressionUnpackState(); |
| + glTexSubImage2D(target, level, xoffset, yoffset, width, height, |
| + format_info->decompressed_format, |
| + format_info->decompressed_type, decompressed_data.get()); |
| + state_.RestoreUnpackState(); |
| + } else { |
| + glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, |
| + format, image_size, data); |
| + } |
| // This may be a slow command. Exit command processing to allow for |
| // context preemption and GPU watchdog checks. |
| ExitCommandProcessingEarly(); |
| + return error::kNoError; |
| } |
| static void Clip( |
| @@ -15098,13 +15342,22 @@ void GLES2DecoderImpl::TexStorageImpl(GLenum target, |
| } |
| } |
| + GLenum compatibility_internal_format = internal_format; |
| + const CompressedFormatInfo* format_info = |
| + GetCompressedFormatInfo(internal_format); |
| + if (format_info != nullptr && !format_info->support_check(*feature_info_)) { |
| + compatibility_internal_format = format_info->decompressed_internal_format; |
| + } |
| + |
| // TODO(zmo): We might need to emulate TexStorage using TexImage or |
| // CompressedTexImage on Mac OSX where we expose ES3 APIs when the underlying |
| // driver is lower than 4.2 and ARB_texture_storage extension doesn't exist. |
| if (dimension == ContextState::k2D) { |
| - glTexStorage2DEXT(target, levels, internal_format, width, height); |
| + glTexStorage2DEXT(target, levels, compatibility_internal_format, width, |
| + height); |
| } else { |
| - glTexStorage3D(target, levels, internal_format, width, height, depth); |
| + glTexStorage3D(target, levels, compatibility_internal_format, width, height, |
| + depth); |
| } |
| { |