Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(589)

Unified Diff: gpu/command_buffer/service/gles2_cmd_decoder.cc

Issue 2076213002: Decompress ETC texture data when there is no native support. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix unpack alignment Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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..323f0dea3c0385a44b94fde9cc56a0b067351843 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"
@@ -11482,6 +11483,149 @@ 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);
piman 2016/07/08 19:30:39 nit: no need for the outer set of parens.
Geoff Lang 2016/07/11 19:19:07 Done.
+ 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,
piman 2016/07/08 19:30:39 The buffer might already be mapped, in which case
Geoff Lang 2016/07/11 19:19:08 I updated the validation code to cover these cases
+ reinterpret_cast<GLintptr>(data), image_size,
+ GL_MAP_READ_BIT);
+ }
+
+ info.decompression_function(
+ width, height, depth, reinterpret_cast<const uint8_t*>(input_data),
piman 2016/07/08 19:30:39 nit: static_cast instead of reinterpret_cast
Geoff Lang 2016/07/11 19:19:08 Done.
+ 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) {
+ glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
piman 2016/07/08 19:30:39 glUnmapBuffer is allowed to fail, corrupting the d
Geoff Lang 2016/07/11 19:19:08 Done, I had to modify the command buffer generatio
+ }
+
+ return decompressed_data;
+}
+
+void PushDecompressedTextureUnpackState() {
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
Zhenyao Mo 2016/07/08 22:40:29 nit: the above three lines can be put inside the c
Geoff Lang 2016/07/11 19:19:08 Done, moved all the logic into ContextState.
+}
+
+void PopDecompressedTextureUnpackState(const ContextState& state) {
+ state.RestoreUnpackState();
+}
+
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.
@@ -11905,14 +12049,27 @@ 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);
+ PushDecompressedTextureUnpackState();
+ glTexImage2D(target, level, format_info->decompressed_internal_format,
+ width, height, border, format_info->decompressed_format,
+ format_info->decompressed_type, decompressed_data.get());
+ PopDecompressedTextureUnpackState(state_);
+ } 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,
@@ -11977,14 +12134,26 @@ 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);
+ PushDecompressedTextureUnpackState();
+ glTexImage3D(target, level, format_info->decompressed_internal_format,
+ width, height, depth, border, format_info->decompressed_format,
+ format_info->decompressed_type, decompressed_data.get());
+ PopDecompressedTextureUnpackState(state_);
+ } 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,
@@ -12049,9 +12218,21 @@ void GLES2DecoderImpl::DoCompressedTexSubImage3D(
// 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);
+ PushDecompressedTextureUnpackState();
+ glTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height,
+ depth, format_info->decompressed_format,
+ format_info->decompressed_type, decompressed_data.get());
+ PopDecompressedTextureUnpackState(state_);
+ } 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.
@@ -12300,8 +12481,20 @@ 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);
+ PushDecompressedTextureUnpackState();
+ glTexSubImage2D(target, level, xoffset, yoffset, width, height,
+ format_info->decompressed_format,
+ format_info->decompressed_type, decompressed_data.get());
+ PopDecompressedTextureUnpackState(state_);
+ } 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.
@@ -15098,13 +15291,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);
}
{

Powered by Google App Engine
This is Rietveld 408576698