| // Copyright 2016 The Chromium Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "gpu/command_buffer/service/gl_utils.h" | |
| #include <algorithm> | |
| #include <array> | |
| #include <unordered_set> | |
| #include "base/compiler_specific.h" | |
| #include "base/containers/span.h" | |
| #include "base/strings/strcat.h" | |
| #include "build/build_config.h" | |
| #include "gpu/command_buffer/common/capabilities.h" | |
| #include "gpu/command_buffer/service/error_state.h" | |
| #include "gpu/command_buffer/service/feature_info.h" | |
| #include "gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h" | |
| #include "gpu/command_buffer/service/logger.h" | |
| #include "gpu/command_buffer/service/texture_manager.h" | |
| #include "ui/gl/gl_utils.h" | |
| #include "ui/gl/gl_version_info.h" | |
| #if BUILDFLAG(IS_CHROMEOS) | |
| #include <sys/stat.h> | |
| #include "ui/gfx/linux/drm_util_linux.h" // nogncheck | |
| #include "ui/gfx/native_pixmap_handle.h" | |
| #include "ui/gl/gl_surface_egl.h" | |
| #include "ui/ozone/public/ozone_platform.h" | |
| #include "ui/ozone/public/surface_factory_ozone.h" | |
| #endif | |
| namespace gpu { | |
| namespace gles2 { | |
| namespace { | |
| const int kASTCBlockSize = 16; | |
| const int kS3TCBlockWidth = 4; | |
| const int kS3TCBlockHeight = 4; | |
| const int kS3TCDXT1BlockSize = 8; | |
| const int kS3TCDXT3AndDXT5BlockSize = 16; | |
| const int kEACAndETC2BlockSize = 4; | |
| const int kBPTCBlockWidth = 4; | |
| const int kBPTCBlockHeight = 4; | |
| const int kRGTCBlockWidth = 4; | |
| const int kRGTCBlockHeight = 4; | |
| typedef struct { | |
| int blockWidth; | |
| int blockHeight; | |
| } ASTCBlockArray; | |
| const auto kASTCBlockArray = std::to_array<ASTCBlockArray>({ | |
| {4, 4}, /* GL_COMPRESSED_RGBA_ASTC_4x4_KHR */ | |
| {5, 4}, /* and GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR */ | |
| {5, 5}, | |
| {6, 5}, | |
| {6, 6}, | |
| {8, 5}, | |
| {8, 6}, | |
| {8, 8}, | |
| {10, 5}, | |
| {10, 6}, | |
| {10, 8}, | |
| {10, 10}, | |
| {12, 10}, | |
| {12, 12}, | |
| }); | |
| bool IsValidPVRTCSize(GLint level, GLsizei size) { | |
| return GLES2Util::IsPOT(size); | |
| } | |
| bool IsValidS3TCSizeForWebGLAndANGLE(GLint level, GLsizei size) { | |
| // WebGL and ANGLE only allow multiple-of-4 sizes for the base level. See | |
| // WEBGL_compressed_texture_s3tc and ANGLE_compressed_texture_dxt* | |
| return (level > 0) || (size % kS3TCBlockWidth == 0); | |
| } | |
| } // namespace | |
| bool PrecisionMeetsSpecForHighpFloat(GLint rangeMin, | |
| GLint rangeMax, | |
| GLint precision) { | |
| return (rangeMin >= 62) && (rangeMax >= 62) && (precision >= 16); | |
| } | |
| void QueryShaderPrecisionFormat(GLenum shader_type, | |
| GLenum precision_type, | |
| base::span<GLint> range, | |
| GLint* precision) { | |
| switch (precision_type) { | |
| case GL_LOW_INT: | |
| case GL_MEDIUM_INT: | |
| case GL_HIGH_INT: | |
| // These values are for a 32-bit twos-complement integer format. | |
| range[0] = 31; | |
| range[1] = 30; | |
| *precision = 0; | |
| break; | |
| case GL_LOW_FLOAT: | |
| case GL_MEDIUM_FLOAT: | |
| case GL_HIGH_FLOAT: | |
| // These values are for an IEEE single-precision floating-point format. | |
| range[0] = 127; | |
| range[1] = 127; | |
| *precision = 23; | |
| break; | |
| default: | |
| NOTREACHED(); | |
| } | |
| // This function is sometimes defined even though it's really just | |
| // a stub, so we need to set range and precision as if it weren't | |
| // defined before calling it. | |
| // On Mac OS with some GPUs, calling this generates a | |
| // GL_INVALID_OPERATION error. Avoid calling it on non-GLES2 | |
| // platforms. | |
| glGetShaderPrecisionFormat(shader_type, precision_type, range.data(), | |
| precision); | |
| // TODO(brianderson): Make the following official workarounds. | |
| // Some drivers have bugs where they report the ranges as a negative number. | |
| // Taking the absolute value here shouldn't hurt because negative numbers | |
| // aren't expected anyway. | |
| range[0] = abs(range[0]); | |
| range[1] = abs(range[1]); | |
| // If the driver reports a precision for highp float that isn't actually | |
| // highp, don't pretend like it's supported because shader compilation will | |
| // fail anyway. | |
| if (precision_type == GL_HIGH_FLOAT && | |
| !PrecisionMeetsSpecForHighpFloat(range[0], range[1], *precision)) { | |
| range[0] = 0; | |
| range[1] = 0; | |
| *precision = 0; | |
| } | |
| } | |
| void PopulateNumericCapabilities(Capabilities* caps, | |
| const FeatureInfo* feature_info) { | |
| DCHECK(caps != nullptr); | |
| glGetIntegerv(GL_MAX_TEXTURE_SIZE, &caps->max_texture_size); | |
| } | |
| void PopulateGLCapabilities(GLCapabilities* caps, | |
| const FeatureInfo* feature_info) { | |
| CHECK(caps); | |
| caps->VisitPrecisions([](GLenum shader, GLenum type, | |
| GLCapabilities::ShaderPrecision* shader_precision) { | |
| GLint range[2] = {0, 0}; | |
| GLint precision = 0; | |
| QueryShaderPrecisionFormat(shader, type, range, &precision); | |
| shader_precision->min_range = range[0]; | |
| shader_precision->max_range = range[1]; | |
| shader_precision->precision = precision; | |
| }); | |
| glGetIntegerv(GL_MAX_TEXTURE_SIZE, &caps->max_texture_size); | |
| glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, | |
| &caps->max_combined_texture_image_units); | |
| glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &caps->max_cube_map_texture_size); | |
| glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, | |
| &caps->max_fragment_uniform_vectors); | |
| glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &caps->max_renderbuffer_size); | |
| glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &caps->max_texture_image_units); | |
| if (feature_info->workarounds().max_texture_image_units_13) { | |
| caps->max_texture_image_units = std::min(caps->max_texture_image_units, 13); | |
| } | |
| glGetIntegerv(GL_MAX_VARYING_VECTORS, &caps->max_varying_vectors); | |
| glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &caps->max_vertex_attribs); | |
| glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, | |
| &caps->max_vertex_texture_image_units); | |
| glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, | |
| &caps->max_vertex_uniform_vectors); | |
| { | |
| GLint dims[2] = {0, 0}; | |
| glGetIntegerv(GL_MAX_VIEWPORT_DIMS, dims); | |
| caps->max_viewport_width = dims[0]; | |
| caps->max_viewport_height = dims[1]; | |
| } | |
| glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, | |
| &caps->num_compressed_texture_formats); | |
| glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &caps->num_shader_binary_formats); | |
| if (feature_info->IsWebGL2OrES3OrHigherContext()) { | |
| glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &caps->max_3d_texture_size); | |
| glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &caps->max_array_texture_layers); | |
| glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &caps->max_color_attachments); | |
| glGetInteger64v(GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS, | |
| &caps->max_combined_fragment_uniform_components); | |
| glGetIntegerv(GL_MAX_COMBINED_UNIFORM_BLOCKS, | |
| &caps->max_combined_uniform_blocks); | |
| glGetInteger64v(GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS, | |
| &caps->max_combined_vertex_uniform_components); | |
| glGetIntegerv(GL_MAX_DRAW_BUFFERS, &caps->max_draw_buffers); | |
| glGetInteger64v(GL_MAX_ELEMENT_INDEX, &caps->max_element_index); | |
| glGetIntegerv(GL_MAX_ELEMENTS_INDICES, &caps->max_elements_indices); | |
| glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &caps->max_elements_vertices); | |
| glGetIntegerv(GL_MAX_FRAGMENT_INPUT_COMPONENTS, | |
| &caps->max_fragment_input_components); | |
| glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_BLOCKS, | |
| &caps->max_fragment_uniform_blocks); | |
| glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, | |
| &caps->max_fragment_uniform_components); | |
| glGetIntegerv(GL_MAX_PROGRAM_TEXEL_OFFSET, &caps->max_program_texel_offset); | |
| glGetInteger64v(GL_MAX_SERVER_WAIT_TIMEOUT, &caps->max_server_wait_timeout); | |
| glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &caps->max_texture_lod_bias); | |
| glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, | |
| &caps->max_transform_feedback_interleaved_components); | |
| glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, | |
| &caps->max_transform_feedback_separate_attribs); | |
| glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS, | |
| &caps->max_transform_feedback_separate_components); | |
| glGetInteger64v(GL_MAX_UNIFORM_BLOCK_SIZE, &caps->max_uniform_block_size); | |
| glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, | |
| &caps->max_uniform_buffer_bindings); | |
| glGetIntegerv(GL_MAX_VARYING_COMPONENTS, &caps->max_varying_components); | |
| glGetIntegerv(GL_MAX_VERTEX_OUTPUT_COMPONENTS, | |
| &caps->max_vertex_output_components); | |
| glGetIntegerv(GL_MAX_VERTEX_UNIFORM_BLOCKS, | |
| &caps->max_vertex_uniform_blocks); | |
| glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, | |
| &caps->max_vertex_uniform_components); | |
| glGetIntegerv(GL_MIN_PROGRAM_TEXEL_OFFSET, &caps->min_program_texel_offset); | |
| glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, | |
| &caps->num_program_binary_formats); | |
| glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, | |
| &caps->uniform_buffer_offset_alignment); | |
| } | |
| if (feature_info->feature_flags().multisampled_render_to_texture || | |
| feature_info->feature_flags().chromium_framebuffer_multisample || | |
| feature_info->IsWebGL2OrES3OrHigherContext()) { | |
| glGetIntegerv(GL_MAX_SAMPLES, &caps->max_samples); | |
| } | |
| if (feature_info->IsWebGL2OrES3OrHigherContext()) { | |
| caps->major_version = 3; | |
| caps->minor_version = 0; | |
| } | |
| } | |
| #if BUILDFLAG(IS_CHROMEOS) | |
| void PopulateMappableDrmFormatsForExo( | |
| base::flat_map<uint32_t, std::vector<uint64_t>>& drm_formats_and_modifiers, | |
| const FeatureInfo* feature_info) { | |
| // Populate list of supported mappable formats based on FeatureFlags. | |
| base::flat_set<viz::SharedImageFormat> mappable_formats = { | |
| viz::SinglePlaneFormat::kBGR_565, // | |
| viz::SinglePlaneFormat::kRGBA_8888, // | |
| viz::SinglePlaneFormat::kRGBX_8888, // | |
| viz::MultiPlaneFormat::kYV12, // | |
| viz::MultiPlaneFormat::kNV12, // | |
| }; | |
| const auto& flags = feature_info->feature_flags(); | |
| if (flags.enable_texture_half_float_linear) { | |
| mappable_formats.insert(viz::SinglePlaneFormat::kRGBA_F16); | |
| } | |
| if (flags.ext_texture_format_bgra8888) { | |
| mappable_formats.insert(viz::SinglePlaneFormat::kBGRA_8888); | |
| mappable_formats.insert(viz::SinglePlaneFormat::kBGRX_8888); | |
| } | |
| if (flags.chromium_image_ab30) { | |
| mappable_formats.insert(viz::SinglePlaneFormat::kRGBA_1010102); | |
| } | |
| auto* surface_factory = | |
| ui::OzonePlatform::GetInstance()->GetSurfaceFactoryOzone(); | |
| if (surface_factory->IsFormatSupportedForTexturing( | |
| viz::MultiPlaneFormat::kP010)) { | |
| mappable_formats.insert(viz::MultiPlaneFormat::kP010); | |
| } | |
| // Remove unexpected Drm formats from already populated list. | |
| base::EraseIf(drm_formats_and_modifiers, [&](const auto& format) { | |
| auto drm_format = format.first; | |
| return !ui::IsValidDrmFormat(drm_format) || | |
| !mappable_formats.contains( | |
| ui::GetSharedImageFormatFromFourCCFormat(drm_format)); | |
| }); | |
| // If the list is empty, populate with invalid modifiers for mappable formats. | |
| if (drm_formats_and_modifiers.empty()) { | |
| for (auto format : mappable_formats) { | |
| int drm_format = ui::GetFourCCFormatFromSharedImageFormat(format); | |
| // NativePixmapHandle::kNoModifier is equivalent to | |
| // DRM_FORMAT_MOD_INVALID. | |
| std::vector<uint64_t> modifiers = {gfx::NativePixmapHandle::kNoModifier}; | |
| drm_formats_and_modifiers.emplace(drm_format, modifiers); | |
| } | |
| } | |
| } | |
| void PopulateDRMCapabilities(Capabilities* caps, | |
| const FeatureInfo* feature_info) { | |
| DCHECK(caps != nullptr); | |
| if (!gl::GLSurfaceEGL::GetGLDisplayEGL() || | |
| !gl::GLSurfaceEGL::GetGLDisplayEGL()->IsInitialized() || | |
| !gl::GLSurfaceEGL::GetGLDisplayEGL() | |
| ->ext->b_EGL_EXT_image_dma_buf_import_modifiers || | |
| feature_info->workarounds() | |
| .disable_egl_ext_image_dma_buf_import_modifiers || | |
| !gl::g_driver_egl.client_ext.b_EGL_EXT_device_query) { | |
| return; | |
| } | |
| EGLDisplay egl_display = gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay(); | |
| DCHECK(egl_display != nullptr); | |
| EGLDeviceEXT egl_device; | |
| if (!eglQueryDisplayAttribEXT(egl_display, EGL_DEVICE_EXT, | |
| (EGLAttrib*)&egl_device)) { | |
| return; | |
| } | |
| gfx::ExtensionSet device_extension_set; | |
| const char* device_extensions = | |
| eglQueryDeviceStringEXT(egl_device, EGL_EXTENSIONS); | |
| if (device_extensions) { | |
| device_extension_set = gfx::MakeExtensionSet(device_extensions); | |
| } else { | |
| device_extension_set = gfx::ExtensionSet(); | |
| } | |
| std::string drm_render_node; | |
| if (gfx::HasExtension(device_extension_set, | |
| "EGL_EXT_device_drm_render_node")) { | |
| const char* path = | |
| eglQueryDeviceStringEXT(egl_device, EGL_DRM_RENDER_NODE_FILE_EXT); | |
| if (path) | |
| drm_render_node = std::string(path); | |
| } | |
| if (drm_render_node.empty() && | |
| gfx::HasExtension(device_extension_set, "EGL_EXT_device_drm")) { | |
| const char* path = | |
| eglQueryDeviceStringEXT(egl_device, EGL_DRM_DEVICE_FILE_EXT); | |
| if (path) | |
| drm_render_node = std::string(path); | |
| } | |
| if (!drm_render_node.empty()) { | |
| struct stat dev_stat; | |
| if (stat(drm_render_node.c_str(), &dev_stat) == 0) { | |
| static_assert(sizeof(dev_t) <= sizeof(caps->drm_device_id), | |
| "unexpected dev_t size"); | |
| DCHECK(dev_stat.st_rdev); | |
| caps->drm_device_id = dev_stat.st_rdev; | |
| } | |
| } | |
| EGLint num_formats = 0; | |
| if (eglQueryDmaBufFormatsEXT(egl_display, 0, nullptr, &num_formats) && | |
| num_formats > 0) { | |
| std::vector<EGLint> formats_array(num_formats); | |
| bool res = eglQueryDmaBufFormatsEXT(egl_display, num_formats, | |
| formats_array.data(), &num_formats); | |
| DCHECK(res); | |
| for (EGLint format : formats_array) { | |
| std::vector<uint64_t> modifiers; | |
| EGLint num_modifiers = 0; | |
| if (eglQueryDmaBufModifiersEXT(egl_display, format, 0, nullptr, nullptr, | |
| &num_modifiers) && | |
| num_modifiers > 0) { | |
| std::vector<EGLuint64KHR> modifiers_array(num_modifiers); | |
| res = eglQueryDmaBufModifiersEXT(egl_display, format, num_modifiers, | |
| modifiers_array.data(), nullptr, | |
| &num_modifiers); | |
| DCHECK(res); | |
| for (uint64_t modifier : modifiers_array) { | |
| modifiers.push_back(modifier); | |
| } | |
| } | |
| caps->drm_formats_and_modifiers.emplace(format, modifiers); | |
| } | |
| } | |
| } | |
| #endif | |
| bool CheckUniqueAndNonNullIds(GLsizei n, const GLuint* client_ids) { | |
| if (n <= 0) | |
| return true; | |
| std::unordered_set<uint32_t> unique_ids(client_ids, | |
| UNSAFE_TODO(client_ids + n)); | |
| return (unique_ids.size() == static_cast<size_t>(n)) && | |
| (unique_ids.find(0) == unique_ids.end()); | |
| } | |
| const char* GetServiceVersionString(const FeatureInfo* feature_info) { | |
| if (feature_info->IsWebGL2OrES3Context()) { | |
| return "OpenGL ES 3.0 Chromium"; | |
| } else { | |
| return "OpenGL ES 2.0 Chromium"; | |
| } | |
| } | |
| const char* GetServiceShadingLanguageVersionString( | |
| const FeatureInfo* feature_info) { | |
| if (feature_info->IsWebGL2OrES3Context()) { | |
| return "OpenGL ES GLSL ES 3.0 Chromium"; | |
| } else { | |
| return "OpenGL ES GLSL ES 1.0 Chromium"; | |
| } | |
| } | |
| void LogGLDebugMessage(GLenum source, | |
| GLenum type, | |
| GLuint id, | |
| GLenum severity, | |
| GLsizei length, | |
| const GLchar* message, | |
| Logger* error_logger) { | |
| std::string id_string = GLES2Util::GetStringEnum(id); | |
| // Suppresses GL_DEBUG_TYPE_PERFORMANCE log messages for web tests that can | |
| // get sent to the JS console and cause unnecessary test failures due test | |
| // output log expectation comparisons. | |
| if (type == GL_DEBUG_TYPE_PERFORMANCE && | |
| error_logger->SuppressPerformanceLogs()) { | |
| return; | |
| } else if (type == GL_DEBUG_TYPE_ERROR && source == GL_DEBUG_SOURCE_API) { | |
| error_logger->LogMessage(__FILE__, __LINE__, | |
| " " + id_string + ": " + message); | |
| } else { | |
| error_logger->LogMessage( | |
| __FILE__, __LINE__, | |
| base::StrCat({"GL Driver Message (", gl::GetDebugSourceString(source), | |
| ", ", gl::GetDebugTypeString(type), ", ", id_string, ", ", | |
| gl::GetDebugSeverityString(severity), "): ", message})); | |
| } | |
| } | |
| void InitializeGLDebugLogging(bool log_non_errors, | |
| GLDEBUGPROC callback, | |
| const void* user_param) { | |
| glEnable(GL_DEBUG_OUTPUT); | |
| glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); | |
| glDebugMessageControlKHR(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_ERROR, | |
| GL_DONT_CARE, 0, nullptr, GL_TRUE); | |
| if (log_non_errors) { | |
| // Enable logging of medium and high severity messages | |
| glDebugMessageControlKHR(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH, | |
| 0, nullptr, GL_TRUE); | |
| glDebugMessageControlKHR(GL_DONT_CARE, GL_DONT_CARE, | |
| GL_DEBUG_SEVERITY_MEDIUM, 0, nullptr, GL_TRUE); | |
| glDebugMessageControlKHR(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW, | |
| 0, nullptr, GL_FALSE); | |
| glDebugMessageControlKHR(GL_DONT_CARE, GL_DONT_CARE, | |
| GL_DEBUG_SEVERITY_NOTIFICATION, 0, nullptr, | |
| GL_FALSE); | |
| // Enable special messages from ANGLE used to experiment with disabling | |
| // obscure features of webgl. | |
| glDebugMessageControlKHR(GL_DEBUG_SOURCE_OTHER, GL_DEBUG_TYPE_PORTABILITY, | |
| GL_DONT_CARE, 0, nullptr, GL_TRUE); | |
| } | |
| glDebugMessageCallbackKHR(callback, user_param); | |
| } | |
| bool ValidContextLostReason(GLenum reason) { | |
| switch (reason) { | |
| case GL_NO_ERROR: | |
| case GL_GUILTY_CONTEXT_RESET: | |
| case GL_INNOCENT_CONTEXT_RESET: | |
| case GL_UNKNOWN_CONTEXT_RESET: | |
| return true; | |
| default: | |
| return false; | |
| } | |
| } | |
| error::ContextLostReason GetContextLostReasonFromResetStatus( | |
| GLenum reset_status) { | |
| switch (reset_status) { | |
| case GL_NO_ERROR: | |
| // TODO(kbr): improve the precision of the error code in this case. | |
| // Consider delegating to context for error code if MakeCurrent fails. | |
| return error::kUnknown; | |
| case GL_GUILTY_CONTEXT_RESET: | |
| return error::kGuilty; | |
| case GL_INNOCENT_CONTEXT_RESET: | |
| return error::kInnocent; | |
| case GL_UNKNOWN_CONTEXT_RESET: | |
| return error::kUnknown; | |
| } | |
| NOTREACHED(); | |
| } | |
| gfx::Vector2d GetCompressedTexBlockDimensions(GLenum format) { | |
| switch (format) { | |
| case GL_ATC_RGB_AMD: | |
| case GL_ATC_RGBA_EXPLICIT_ALPHA_AMD: | |
| case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD: | |
| case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: | |
| case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: | |
| case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: | |
| case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: | |
| case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: | |
| case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: | |
| case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: | |
| case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: | |
| case GL_ETC1_RGB8_OES: | |
| return gfx::Vector2d(kS3TCBlockWidth, kS3TCBlockHeight); | |
| case GL_COMPRESSED_RGBA_ASTC_4x4_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_5x4_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_5x5_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_6x5_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_6x6_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_8x5_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_8x6_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_8x8_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_10x5_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_10x6_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_10x8_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_10x10_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_12x10_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_12x12_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: { | |
| const int index = | |
| (format < GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR) | |
| ? static_cast<int>(format - GL_COMPRESSED_RGBA_ASTC_4x4_KHR) | |
| : static_cast<int>(format - | |
| GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR); | |
| return gfx::Vector2d(kASTCBlockArray[index].blockWidth, | |
| kASTCBlockArray[index].blockHeight); | |
| } | |
| case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG: | |
| case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG: | |
| return gfx::Vector2d(4, 4); | |
| case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG: | |
| case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: | |
| return gfx::Vector2d(8, 4); | |
| case GL_COMPRESSED_R11_EAC: | |
| case GL_COMPRESSED_SIGNED_R11_EAC: | |
| case GL_COMPRESSED_RGB8_ETC2: | |
| case GL_COMPRESSED_SRGB8_ETC2: | |
| case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: | |
| case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: | |
| case GL_COMPRESSED_RG11_EAC: | |
| case GL_COMPRESSED_SIGNED_RG11_EAC: | |
| case GL_COMPRESSED_RGBA8_ETC2_EAC: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: | |
| return gfx::Vector2d(kEACAndETC2BlockSize, kEACAndETC2BlockSize); | |
| case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT: | |
| case GL_COMPRESSED_RGBA_BPTC_UNORM_EXT: | |
| case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT: | |
| case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT: | |
| return gfx::Vector2d(kBPTCBlockWidth, kBPTCBlockHeight); | |
| case GL_COMPRESSED_RED_RGTC1_EXT: | |
| case GL_COMPRESSED_SIGNED_RED_RGTC1_EXT: | |
| case GL_COMPRESSED_RED_GREEN_RGTC2_EXT: | |
| case GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT: | |
| return gfx::Vector2d(kRGTCBlockWidth, kRGTCBlockHeight); | |
| default: | |
| return gfx::Vector2d(1, 1); | |
| } | |
| } | |
| bool GetCompressedTexSizeInBytes(const char* function_name, | |
| GLsizei width, | |
| GLsizei height, | |
| GLsizei depth, | |
| GLenum format, | |
| GLsizei* size_in_bytes, | |
| ErrorState* error_state) { | |
| base::CheckedNumeric<GLsizei> bytes_required(0); | |
| switch (format) { | |
| case GL_ATC_RGB_AMD: | |
| case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: | |
| case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: | |
| case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: | |
| case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: | |
| case GL_ETC1_RGB8_OES: | |
| bytes_required = base::CheckDiv( | |
| base::CheckAdd(width, kS3TCBlockWidth - 1), kS3TCBlockWidth); | |
| bytes_required *= base::CheckDiv( | |
| base::CheckAdd(height, kS3TCBlockHeight - 1), kS3TCBlockHeight); | |
| bytes_required *= kS3TCDXT1BlockSize; | |
| break; | |
| case GL_COMPRESSED_RGBA_ASTC_4x4_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_5x4_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_5x5_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_6x5_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_6x6_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_8x5_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_8x6_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_8x8_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_10x5_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_10x6_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_10x8_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_10x10_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_12x10_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_12x12_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: { | |
| const int index = | |
| (format < GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR) | |
| ? static_cast<int>(format - GL_COMPRESSED_RGBA_ASTC_4x4_KHR) | |
| : static_cast<int>(format - | |
| GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR); | |
| const int kBlockWidth = kASTCBlockArray[index].blockWidth; | |
| const int kBlockHeight = kASTCBlockArray[index].blockHeight; | |
| bytes_required = | |
| base::CheckDiv(base::CheckAdd(width, kBlockWidth - 1), kBlockWidth); | |
| bytes_required *= base::CheckDiv(base::CheckAdd(height, kBlockHeight - 1), | |
| kBlockHeight); | |
| bytes_required *= kASTCBlockSize; | |
| break; | |
| } | |
| case GL_ATC_RGBA_EXPLICIT_ALPHA_AMD: | |
| case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD: | |
| case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: | |
| case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: | |
| case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: | |
| case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: | |
| bytes_required = base::CheckDiv( | |
| base::CheckAdd(width, kS3TCBlockWidth - 1), kS3TCBlockWidth); | |
| bytes_required *= base::CheckDiv( | |
| base::CheckAdd(height, kS3TCBlockHeight - 1), kS3TCBlockHeight); | |
| bytes_required *= kS3TCDXT3AndDXT5BlockSize; | |
| break; | |
| case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG: | |
| case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG: | |
| bytes_required = std::max(width, 8); | |
| bytes_required *= std::max(height, 8); | |
| bytes_required *= 4; | |
| bytes_required += 7; | |
| bytes_required /= 8; | |
| break; | |
| case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG: | |
| case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: | |
| bytes_required = std::max(width, 16); | |
| bytes_required *= std::max(height, 8); | |
| bytes_required *= 2; | |
| bytes_required += 7; | |
| bytes_required /= 8; | |
| break; | |
| // ES3 formats. | |
| case GL_COMPRESSED_R11_EAC: | |
| case GL_COMPRESSED_SIGNED_R11_EAC: | |
| case GL_COMPRESSED_RGB8_ETC2: | |
| case GL_COMPRESSED_SRGB8_ETC2: | |
| case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: | |
| case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: | |
| bytes_required = | |
| base::CheckDiv(base::CheckAdd(width, kEACAndETC2BlockSize - 1), | |
| kEACAndETC2BlockSize); | |
| bytes_required *= | |
| base::CheckDiv(base::CheckAdd(height, kEACAndETC2BlockSize - 1), | |
| kEACAndETC2BlockSize); | |
| bytes_required *= 8; | |
| break; | |
| case GL_COMPRESSED_RG11_EAC: | |
| case GL_COMPRESSED_SIGNED_RG11_EAC: | |
| case GL_COMPRESSED_RGBA8_ETC2_EAC: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: | |
| bytes_required = | |
| base::CheckDiv(base::CheckAdd(width, kEACAndETC2BlockSize - 1), | |
| kEACAndETC2BlockSize); | |
| bytes_required *= | |
| base::CheckDiv(base::CheckAdd(height, kEACAndETC2BlockSize - 1), | |
| kEACAndETC2BlockSize); | |
| bytes_required *= 16; | |
| break; | |
| case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT: | |
| case GL_COMPRESSED_RGBA_BPTC_UNORM_EXT: | |
| case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT: | |
| case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT: | |
| bytes_required = base::CheckDiv( | |
| base::CheckAdd(width, kBPTCBlockWidth - 1), kBPTCBlockWidth); | |
| bytes_required *= base::CheckDiv( | |
| base::CheckAdd(height, kBPTCBlockHeight - 1), kBPTCBlockHeight); | |
| bytes_required *= 16; | |
| break; | |
| case GL_COMPRESSED_RED_RGTC1_EXT: | |
| case GL_COMPRESSED_SIGNED_RED_RGTC1_EXT: | |
| bytes_required = base::CheckDiv( | |
| base::CheckAdd(width, kRGTCBlockWidth - 1), kRGTCBlockWidth); | |
| bytes_required *= base::CheckDiv( | |
| base::CheckAdd(height, kRGTCBlockHeight - 1), kRGTCBlockHeight); | |
| bytes_required *= 8; | |
| break; | |
| case GL_COMPRESSED_RED_GREEN_RGTC2_EXT: | |
| case GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT: | |
| bytes_required = base::CheckDiv( | |
| base::CheckAdd(width, kRGTCBlockWidth - 1), kRGTCBlockWidth); | |
| bytes_required *= base::CheckDiv( | |
| base::CheckAdd(height, kRGTCBlockHeight - 1), kRGTCBlockHeight); | |
| bytes_required *= 16; | |
| break; | |
| default: | |
| if (function_name && error_state) { | |
| ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(error_state, function_name, format, | |
| "format"); | |
| } | |
| return false; | |
| } | |
| bytes_required *= depth; | |
| if (!bytes_required.IsValid()) { | |
| if (function_name && error_state) { | |
| ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_VALUE, function_name, | |
| "invalid size"); | |
| } | |
| return false; | |
| } | |
| *size_in_bytes = bytes_required.ValueOrDefault(0); | |
| return true; | |
| } | |
| bool ValidateCompressedFormatTarget(GLenum target, GLenum format) { | |
| if (target == GL_TEXTURE_3D) { | |
| // Formats not supporting 3D Tex | |
| switch (format) { | |
| // ES 3.1, Section 8.7, page 169. | |
| case GL_COMPRESSED_R11_EAC: | |
| case GL_COMPRESSED_SIGNED_R11_EAC: | |
| case GL_COMPRESSED_RG11_EAC: | |
| case GL_COMPRESSED_SIGNED_RG11_EAC: | |
| case GL_COMPRESSED_RGB8_ETC2: | |
| case GL_COMPRESSED_SRGB8_ETC2: | |
| case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: | |
| case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: | |
| case GL_COMPRESSED_RGBA8_ETC2_EAC: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: | |
| // GL_EXT_texture_compression_s3tc | |
| case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: | |
| case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: | |
| case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: | |
| case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: | |
| case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: | |
| case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: | |
| case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: | |
| case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: | |
| // GL_EXT_texture_compression_rgtc | |
| case GL_COMPRESSED_RED_RGTC1_EXT: | |
| case GL_COMPRESSED_SIGNED_RED_RGTC1_EXT: | |
| case GL_COMPRESSED_RED_GREEN_RGTC2_EXT: | |
| case GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT: | |
| return false; | |
| // GL_KHR_texture_compression_astc_hdr, TEXTURE_3D is not supported | |
| // without HDR profile. This is guaranteed to be validated beforehand | |
| // in GLES2DecoderImpl::TexStorageImpl before calling this. | |
| default: | |
| break; | |
| } | |
| } | |
| return true; | |
| } | |
| bool ValidateCompressedTexSubDimensions(GLenum target, | |
| GLint level, | |
| GLint xoffset, | |
| GLint yoffset, | |
| GLint zoffset, | |
| GLsizei width, | |
| GLsizei height, | |
| GLsizei depth, | |
| GLenum format, | |
| Texture* texture, | |
| const char** error_message) { | |
| if (!ValidateCompressedFormatTarget(target, format)) { | |
| *error_message = "target invalid for format"; | |
| return false; | |
| } | |
| if (xoffset < 0 || yoffset < 0 || zoffset < 0) { | |
| *error_message = "x/y/z offset < 0"; | |
| return false; | |
| } | |
| switch (format) { | |
| case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: | |
| case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: | |
| case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: | |
| case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: | |
| case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: | |
| case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: | |
| case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: | |
| case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: { | |
| const int kBlockWidth = 4; | |
| const int kBlockHeight = 4; | |
| if ((xoffset % kBlockWidth) || (yoffset % kBlockHeight)) { | |
| *error_message = "xoffset or yoffset not multiple of 4"; | |
| return false; | |
| } | |
| GLsizei tex_width = 0; | |
| GLsizei tex_height = 0; | |
| if (!texture->GetLevelSize(target, level, &tex_width, &tex_height, | |
| nullptr) || | |
| width - xoffset > tex_width || height - yoffset > tex_height) { | |
| *error_message = "dimensions out of range"; | |
| return false; | |
| } | |
| if ((((width % kBlockWidth) != 0) && (width + xoffset != tex_width)) || | |
| (((height % kBlockHeight) != 0) && | |
| (height + yoffset != tex_height))) { | |
| *error_message = "dimensions do not align to a block boundary"; | |
| return false; | |
| } | |
| return true; | |
| } | |
| case GL_COMPRESSED_RGBA_ASTC_4x4_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_5x4_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_5x5_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_6x5_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_6x6_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_8x5_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_8x6_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_8x8_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_10x5_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_10x6_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_10x8_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_10x10_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_12x10_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_12x12_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: { | |
| const int index = | |
| (format < GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR) | |
| ? static_cast<int>(format - GL_COMPRESSED_RGBA_ASTC_4x4_KHR) | |
| : static_cast<int>(format - | |
| GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR); | |
| const int kBlockWidth = kASTCBlockArray[index].blockWidth; | |
| const int kBlockHeight = kASTCBlockArray[index].blockHeight; | |
| if ((xoffset % kBlockWidth) || (yoffset % kBlockHeight)) { | |
| *error_message = "xoffset or yoffset not multiple of 4"; | |
| return false; | |
| } | |
| GLsizei tex_width = 0; | |
| GLsizei tex_height = 0; | |
| if (!texture->GetLevelSize(target, level, &tex_width, &tex_height, | |
| nullptr) || | |
| width - xoffset > tex_width || height - yoffset > tex_height) { | |
| *error_message = "dimensions out of range"; | |
| return false; | |
| } | |
| if ((((width % kBlockWidth) != 0) && (width + xoffset != tex_width)) || | |
| (((height % kBlockHeight) != 0) && | |
| (height + yoffset != tex_height))) { | |
| *error_message = "dimensions do not align to a block boundary"; | |
| return false; | |
| } | |
| return true; | |
| } | |
| case GL_ATC_RGB_AMD: | |
| case GL_ATC_RGBA_EXPLICIT_ALPHA_AMD: | |
| case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD: { | |
| *error_message = "not supported for ATC textures"; | |
| return false; | |
| } | |
| case GL_ETC1_RGB8_OES: { | |
| *error_message = "not supported for ECT1_RGB8_OES textures"; | |
| return false; | |
| } | |
| case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG: | |
| case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG: | |
| case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG: | |
| case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: { | |
| if ((xoffset != 0) || (yoffset != 0)) { | |
| *error_message = "xoffset and yoffset must be zero"; | |
| return false; | |
| } | |
| GLsizei tex_width = 0; | |
| GLsizei tex_height = 0; | |
| if (!texture->GetLevelSize(target, level, &tex_width, &tex_height, | |
| nullptr) || | |
| width != tex_width || height != tex_height) { | |
| *error_message = | |
| "dimensions must match existing texture level dimensions"; | |
| return false; | |
| } | |
| return ValidateCompressedTexDimensions(target, level, width, height, 1, | |
| format, error_message); | |
| } | |
| // ES3 formats | |
| case GL_COMPRESSED_R11_EAC: | |
| case GL_COMPRESSED_SIGNED_R11_EAC: | |
| case GL_COMPRESSED_RG11_EAC: | |
| case GL_COMPRESSED_SIGNED_RG11_EAC: | |
| case GL_COMPRESSED_RGB8_ETC2: | |
| case GL_COMPRESSED_SRGB8_ETC2: | |
| case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: | |
| case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: | |
| case GL_COMPRESSED_RGBA8_ETC2_EAC: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: | |
| case GL_COMPRESSED_RED_RGTC1_EXT: | |
| case GL_COMPRESSED_SIGNED_RED_RGTC1_EXT: | |
| case GL_COMPRESSED_RED_GREEN_RGTC2_EXT: | |
| case GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT: { | |
| if (target == GL_TEXTURE_3D) { | |
| *error_message = "target == GL_TEXTURE_3D is not allowed"; | |
| return false; | |
| } | |
| [[fallthrough]]; | |
| } | |
| case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT: | |
| case GL_COMPRESSED_RGBA_BPTC_UNORM_EXT: | |
| case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT: | |
| case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT: { | |
| const int kBlockSize = 4; | |
| GLsizei tex_width, tex_height; | |
| if (!texture->GetLevelSize(target, level, &tex_width, &tex_height, | |
| nullptr) || | |
| (xoffset % kBlockSize) || (yoffset % kBlockSize) || | |
| ((width % kBlockSize) && xoffset + width != tex_width) || | |
| ((height % kBlockSize) && yoffset + height != tex_height)) { | |
| *error_message = | |
| "dimensions must match existing texture level dimensions"; | |
| return false; | |
| } | |
| return true; | |
| } | |
| default: | |
| *error_message = "unknown compressed texture format"; | |
| return false; | |
| } | |
| } | |
| bool ValidateCompressedTexDimensions(GLenum target, | |
| GLint level, | |
| GLsizei width, | |
| GLsizei height, | |
| GLsizei depth, | |
| GLenum format, | |
| const char** error_message) { | |
| if (!ValidateCompressedFormatTarget(target, format)) { | |
| *error_message = "target invalid for format"; | |
| return false; | |
| } | |
| switch (format) { | |
| case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: | |
| case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: | |
| case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: | |
| case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: | |
| case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: | |
| case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: | |
| case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: | |
| case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: | |
| if (!IsValidS3TCSizeForWebGLAndANGLE(level, width) || | |
| !IsValidS3TCSizeForWebGLAndANGLE(level, height)) { | |
| *error_message = "width or height invalid for level"; | |
| return false; | |
| } | |
| return true; | |
| case GL_COMPRESSED_RGBA_ASTC_4x4_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_5x4_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_5x5_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_6x5_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_6x6_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_8x5_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_8x6_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_8x8_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_10x5_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_10x6_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_10x8_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_10x10_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_12x10_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_12x12_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: | |
| case GL_ATC_RGB_AMD: | |
| case GL_ATC_RGBA_EXPLICIT_ALPHA_AMD: | |
| case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD: | |
| case GL_ETC1_RGB8_OES: | |
| if (width <= 0 || height <= 0) { | |
| *error_message = "width or height invalid for level"; | |
| return false; | |
| } | |
| return true; | |
| case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG: | |
| case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG: | |
| case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG: | |
| case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: | |
| if (!IsValidPVRTCSize(level, width) || !IsValidPVRTCSize(level, height)) { | |
| *error_message = "width or height invalid for level"; | |
| return false; | |
| } | |
| return true; | |
| // ES3 formats. | |
| case GL_COMPRESSED_R11_EAC: | |
| case GL_COMPRESSED_SIGNED_R11_EAC: | |
| case GL_COMPRESSED_RG11_EAC: | |
| case GL_COMPRESSED_SIGNED_RG11_EAC: | |
| case GL_COMPRESSED_RGB8_ETC2: | |
| case GL_COMPRESSED_SRGB8_ETC2: | |
| case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: | |
| case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: | |
| case GL_COMPRESSED_RGBA8_ETC2_EAC: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: | |
| if (width < 0 || height < 0 || depth < 0) { | |
| *error_message = "width, height, or depth invalid"; | |
| return false; | |
| } | |
| return true; | |
| case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT: | |
| case GL_COMPRESSED_RGBA_BPTC_UNORM_EXT: | |
| case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT: | |
| case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT: | |
| if (width < 0 || height < 0 || depth < 0) { | |
| *error_message = "width, height, or depth invalid"; | |
| return false; | |
| } | |
| if (level == 0 && | |
| !(width % kBPTCBlockWidth == 0 && height % kBPTCBlockHeight == 0)) { | |
| *error_message = "width or height is not a multiple of four"; | |
| return false; | |
| } | |
| return true; | |
| case GL_COMPRESSED_RED_RGTC1_EXT: | |
| case GL_COMPRESSED_SIGNED_RED_RGTC1_EXT: | |
| case GL_COMPRESSED_RED_GREEN_RGTC2_EXT: | |
| case GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT: | |
| if (width < 0 || height < 0 || depth < 0) { | |
| *error_message = "width, height, or depth invalid"; | |
| return false; | |
| } | |
| if (level == 0 && | |
| !(width % kRGTCBlockWidth == 0 && height % kRGTCBlockHeight == 0)) { | |
| *error_message = "width or height is not a multiple of four"; | |
| return false; | |
| } | |
| return true; | |
| default: | |
| return false; | |
| } | |
| } | |
| bool ValidateCopyTexFormatHelper(const FeatureInfo* feature_info, | |
| GLenum internal_format, | |
| GLenum read_format, | |
| GLenum read_type, | |
| std::string* output_error_msg) { | |
| DCHECK(output_error_msg); | |
| if (read_format == 0) { | |
| *output_error_msg = std::string("no valid color image"); | |
| return false; | |
| } | |
| // Check we have compatible formats. | |
| uint32_t channels_exist = GLES2Util::GetChannelsForFormat(read_format); | |
| uint32_t channels_needed = GLES2Util::GetChannelsForFormat(internal_format); | |
| if (!channels_needed || | |
| (channels_needed & channels_exist) != channels_needed) { | |
| *output_error_msg = std::string("incompatible format"); | |
| return false; | |
| } | |
| if (feature_info->IsWebGL2OrES3OrHigherContext()) { | |
| GLint color_encoding = | |
| GLES2Util::GetColorEncodingFromInternalFormat(read_format); | |
| bool float_mismatch = feature_info->ext_color_buffer_float_available() | |
| ? (GLES2Util::IsIntegerFormat(internal_format) != | |
| GLES2Util::IsIntegerFormat(read_format)) | |
| : GLES2Util::IsFloatFormat(internal_format); | |
| if (color_encoding != | |
| GLES2Util::GetColorEncodingFromInternalFormat(internal_format) || | |
| float_mismatch || | |
| (GLES2Util::IsSignedIntegerFormat(internal_format) != | |
| GLES2Util::IsSignedIntegerFormat(read_format)) || | |
| (GLES2Util::IsUnsignedIntegerFormat(internal_format) != | |
| GLES2Util::IsUnsignedIntegerFormat(read_format))) { | |
| *output_error_msg = std::string("incompatible format"); | |
| return false; | |
| } | |
| } | |
| if ((channels_needed & (GLES2Util::kDepth | GLES2Util::kStencil)) != 0) { | |
| *output_error_msg = | |
| std::string("can not be used with depth or stencil textures"); | |
| return false; | |
| } | |
| if (feature_info->IsWebGL2OrES3OrHigherContext() || | |
| (feature_info->feature_flags().chromium_color_buffer_float_rgb && | |
| internal_format == GL_RGB32F) || | |
| (feature_info->feature_flags().chromium_color_buffer_float_rgba && | |
| internal_format == GL_RGBA32F)) { | |
| if (GLES2Util::IsSizedColorFormat(internal_format)) { | |
| int sr, sg, sb, sa; | |
| GLES2Util::GetColorFormatComponentSizes(read_format, read_type, &sr, &sg, | |
| &sb, &sa); | |
| DCHECK(sr > 0 || sg > 0 || sb > 0 || sa > 0); | |
| int dr, dg, db, da; | |
| GLES2Util::GetColorFormatComponentSizes(internal_format, 0, &dr, &dg, &db, | |
| &da); | |
| DCHECK(dr > 0 || dg > 0 || db > 0 || da > 0); | |
| if ((dr > 0 && sr != dr) || (dg > 0 && sg != dg) || | |
| (db > 0 && sb != db) || (da > 0 && sa != da)) { | |
| *output_error_msg = std::string("incompatible color component sizes"); | |
| return false; | |
| } | |
| } | |
| } | |
| return true; | |
| } | |
| CopyTextureMethod GetCopyTextureCHROMIUMMethod(const FeatureInfo* feature_info, | |
| GLenum source_target, | |
| GLint source_level, | |
| GLenum source_internal_format, | |
| GLenum source_type, | |
| GLenum dest_target, | |
| GLint dest_level, | |
| GLenum dest_internal_format, | |
| bool flip_y, | |
| bool premultiply_alpha, | |
| bool unpremultiply_alpha) { | |
| bool premultiply_alpha_change = premultiply_alpha ^ unpremultiply_alpha; | |
| bool source_format_color_renderable = | |
| Texture::ColorRenderable(feature_info, source_internal_format, false); | |
| bool dest_format_color_renderable = | |
| Texture::ColorRenderable(feature_info, dest_internal_format, false); | |
| std::string output_error_msg; | |
| switch (dest_internal_format) { | |
| #if BUILDFLAG(IS_MAC) | |
| // RGB5_A1 is not color-renderable on NVIDIA Mac, see | |
| // https://crbug.com/676209. | |
| case GL_RGB5_A1: | |
| return CopyTextureMethod::DRAW_AND_READBACK; | |
| #endif | |
| // RGB9_E5 isn't accepted by glCopyTexImage2D if underlying context is ES. | |
| case GL_RGB9_E5: | |
| return CopyTextureMethod::DRAW_AND_READBACK; | |
| // SRGB format has color-space conversion issue. WebGL spec doesn't define | |
| // clearly if linear-to-srgb color space conversion is required or not when | |
| // uploading DOM elements to SRGB textures. WebGL conformance test expects | |
| // no linear-to-srgb conversion, while current GPU path for | |
| // CopyTextureCHROMIUM does the conversion. Do a fallback path before the | |
| // issue is resolved. see https://github.com/KhronosGroup/WebGL/issues/2165. | |
| // TODO(qiankun.miao@intel.com): revisit this once the above issue is | |
| // resolved. | |
| case GL_SRGB_EXT: | |
| case GL_SRGB_ALPHA_EXT: | |
| case GL_SRGB8: | |
| case GL_SRGB8_ALPHA8: | |
| if (feature_info->IsWebGLContext()) | |
| return CopyTextureMethod::DRAW_AND_READBACK; | |
| break; | |
| default: | |
| break; | |
| } | |
| // CopyTexImage* should not allow internalformat of GL_BGRA_EXT and | |
| // GL_BGRA8_EXT. https://crbug.com/663086. | |
| bool copy_tex_image_format_valid = | |
| source_internal_format != GL_BGRA_EXT && | |
| dest_internal_format != GL_BGRA_EXT && | |
| source_internal_format != GL_BGRA8_EXT && | |
| dest_internal_format != GL_BGRA8_EXT && | |
| ValidateCopyTexFormatHelper(feature_info, dest_internal_format, | |
| source_internal_format, source_type, | |
| &output_error_msg); | |
| // The ES3 spec is vague about whether or not glCopyTexImage2D from a | |
| // GL_RGB10_A2 attachment to an unsized internal format is valid. Most drivers | |
| // interpreted the explicit call out as not valid (and dEQP actually checks | |
| // this), so avoid DIRECT_COPY in that case. | |
| if (source_internal_format == GL_RGB10_A2 && | |
| dest_internal_format != source_internal_format) { | |
| copy_tex_image_format_valid = false; | |
| } | |
| // TODO(qiankun.miao@intel.com): for WebGL 2.0 or OpenGL ES 3.0, both | |
| // DIRECT_DRAW path for dest_level > 0 and DIRECT_COPY path for source_level > | |
| // 0 are not available due to a framebuffer completeness bug: | |
| // https://crbug.com/678526. Once the bug is fixed, the limitation for WebGL | |
| // 2.0 and OpenGL ES 3.0 can be lifted. For WebGL 1.0 or OpenGL ES 2.0, | |
| // DIRECT_DRAW path isn't available for dest_level > 0 due to level > 0 isn't | |
| // supported by glFramebufferTexture2D in ES2 context. DIRECT_DRAW path isn't | |
| // available for cube map dest texture either due to it may be cube map | |
| // incomplete. Go to DRAW_AND_COPY path in these cases. | |
| if (source_target == GL_TEXTURE_2D && | |
| (dest_target == GL_TEXTURE_2D || dest_target == GL_TEXTURE_CUBE_MAP) && | |
| source_format_color_renderable && copy_tex_image_format_valid && | |
| source_level == 0 && !flip_y && !premultiply_alpha_change) { | |
| auto source_texture_type = GLES2Util::GetGLReadPixelsImplementationType( | |
| source_internal_format, source_target); | |
| auto dest_texture_type = GLES2Util::GetGLReadPixelsImplementationType( | |
| dest_internal_format, dest_target); | |
| if (source_texture_type != GL_UNSIGNED_SHORT || | |
| source_texture_type == dest_texture_type) { | |
| // https://crbug.com/1042239. As it is stated in the latest OpenGL ES 3.2 | |
| // spec (Oct 22, 2019) it is optional for implementation to support | |
| // conversion between unmatched source and dest effective internal format. | |
| // R16 to R16F direct copy failure is seen on Android Nvidia shield | |
| // devices. So we won't use DIRECT_COPY for this format. | |
| return CopyTextureMethod::DIRECT_COPY; | |
| } | |
| } | |
| if (dest_format_color_renderable && dest_level == 0 && | |
| dest_target != GL_TEXTURE_CUBE_MAP) | |
| return CopyTextureMethod::DIRECT_DRAW; | |
| // Draw to a fbo attaching level 0 of an intermediate texture, | |
| // then copy from the fbo to dest texture level with glCopyTexImage2D. | |
| return CopyTextureMethod::DRAW_AND_COPY; | |
| } | |
| bool ValidateCopyTextureCHROMIUMInternalFormats(const FeatureInfo* feature_info, | |
| GLenum source_internal_format, | |
| GLenum dest_internal_format, | |
| std::string* output_error_msg) { | |
| bool valid_dest_format = false; | |
| // TODO(qiankun.miao@intel.com): ALPHA, LUMINANCE and LUMINANCE_ALPHA formats | |
| // are not supported on GL core profile. See https://crbug.com/577144. Enable | |
| // the workaround for glCopyTexImage and glCopyTexSubImage in | |
| // gles2_cmd_copy_tex_image.cc for glCopyTextureCHROMIUM implementation. | |
| switch (dest_internal_format) { | |
| case GL_RGB: | |
| case GL_RGBA: | |
| case GL_RGB8: | |
| case GL_RGBA8: | |
| valid_dest_format = true; | |
| break; | |
| case GL_BGRA_EXT: | |
| case GL_BGRA8_EXT: | |
| valid_dest_format = | |
| feature_info->feature_flags().ext_texture_format_bgra8888; | |
| break; | |
| case GL_SRGB_EXT: | |
| case GL_SRGB_ALPHA_EXT: | |
| valid_dest_format = feature_info->feature_flags().ext_srgb; | |
| break; | |
| case GL_R8: | |
| case GL_R8UI: | |
| case GL_RG8: | |
| case GL_RG8UI: | |
| case GL_SRGB8: | |
| case GL_RGB565: | |
| case GL_RGB8UI: | |
| case GL_SRGB8_ALPHA8: | |
| case GL_RGB5_A1: | |
| case GL_RGBA4: | |
| case GL_RGBA8UI: | |
| case GL_RGB10_A2: | |
| valid_dest_format = feature_info->IsWebGL2OrES3OrHigherContext(); | |
| break; | |
| case GL_RGB9_E5: | |
| case GL_R16F: | |
| case GL_R32F: | |
| case GL_RG16F: | |
| case GL_RG32F: | |
| case GL_RGB16F: | |
| case GL_RGBA16F: | |
| case GL_R11F_G11F_B10F: | |
| valid_dest_format = feature_info->ext_color_buffer_float_available(); | |
| break; | |
| case GL_RGB32F: | |
| valid_dest_format = | |
| feature_info->ext_color_buffer_float_available() || | |
| feature_info->feature_flags().chromium_color_buffer_float_rgb; | |
| break; | |
| case GL_RGBA32F: | |
| valid_dest_format = | |
| feature_info->ext_color_buffer_float_available() || | |
| feature_info->feature_flags().chromium_color_buffer_float_rgba; | |
| break; | |
| case GL_ALPHA: | |
| case GL_LUMINANCE: | |
| case GL_LUMINANCE_ALPHA: | |
| valid_dest_format = true; | |
| break; | |
| default: | |
| valid_dest_format = false; | |
| break; | |
| } | |
| // TODO(aleksandar.stojiljkovic): Use sized internal formats: | |
| // https://crbug.com/628064 | |
| bool valid_source_format = | |
| source_internal_format == GL_RED || source_internal_format == GL_ALPHA || | |
| source_internal_format == GL_RGB || source_internal_format == GL_RGBA || | |
| source_internal_format == GL_RGB8 || source_internal_format == GL_RGBA8 || | |
| source_internal_format == GL_LUMINANCE || | |
| source_internal_format == GL_LUMINANCE_ALPHA || | |
| source_internal_format == GL_BGRA_EXT || | |
| source_internal_format == GL_BGRA8_EXT || | |
| source_internal_format == GL_R16_EXT || | |
| source_internal_format == GL_RG16_EXT || | |
| source_internal_format == GL_RGBA16_EXT || | |
| source_internal_format == GL_RGB10_A2; | |
| if (!valid_source_format) { | |
| *output_error_msg = "invalid source internal format " + | |
| GLES2Util::GetStringEnum(source_internal_format); | |
| return false; | |
| } | |
| if (!valid_dest_format) { | |
| *output_error_msg = "invalid dest internal format " + | |
| GLES2Util::GetStringEnum(dest_internal_format); | |
| return false; | |
| } | |
| return true; | |
| } | |
| GLenum GetTextureBindingQuery(GLenum texture_type) { | |
| switch (texture_type) { | |
| case GL_TEXTURE_2D: | |
| return GL_TEXTURE_BINDING_2D; | |
| case GL_TEXTURE_2D_ARRAY: | |
| return GL_TEXTURE_BINDING_2D_ARRAY; | |
| case GL_TEXTURE_2D_MULTISAMPLE: | |
| return GL_TEXTURE_BINDING_2D_MULTISAMPLE; | |
| case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: | |
| return GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY; | |
| case GL_TEXTURE_3D: | |
| return GL_TEXTURE_BINDING_3D; | |
| case GL_TEXTURE_EXTERNAL_OES: | |
| return GL_TEXTURE_BINDING_EXTERNAL_OES; | |
| case GL_TEXTURE_RECTANGLE_ANGLE: | |
| return GL_TEXTURE_BINDING_RECTANGLE_ANGLE; | |
| case GL_TEXTURE_CUBE_MAP: | |
| return GL_TEXTURE_BINDING_CUBE_MAP; | |
| default: | |
| NOTREACHED(); | |
| } | |
| } | |
| bool IsASTCFormat(GLenum internal_format) { | |
| switch (internal_format) { | |
| case GL_COMPRESSED_RGBA_ASTC_4x4_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_5x4_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_5x5_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_6x5_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_6x6_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_8x5_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_8x6_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_8x8_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_10x5_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_10x6_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_10x8_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_10x10_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_12x10_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_12x12_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: | |
| return true; | |
| default: | |
| break; | |
| } | |
| return false; | |
| } | |
| // This is only called in Texture::SetLevelInfo in texture_manager.cc | |
| // where there is no direct access to decoder->IsCompressedTextureFormat | |
| // or feature_info->validators()->compressed_texture_format.IsValid | |
| bool IsCompressedTextureFormat(GLenum internal_format) { | |
| switch (internal_format) { | |
| // S3TC | |
| case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: | |
| case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: | |
| case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: | |
| case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: | |
| case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: | |
| case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: | |
| case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: | |
| case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: | |
| // ASTC | |
| case GL_COMPRESSED_RGBA_ASTC_4x4_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_5x4_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_5x5_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_6x5_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_6x6_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_8x5_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_8x6_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_8x8_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_10x5_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_10x6_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_10x8_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_10x10_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_12x10_KHR: | |
| case GL_COMPRESSED_RGBA_ASTC_12x12_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: | |
| // BPTC | |
| case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT: | |
| case GL_COMPRESSED_RGBA_BPTC_UNORM_EXT: | |
| case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT: | |
| case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT: | |
| // RGTC | |
| case GL_COMPRESSED_RED_RGTC1_EXT: | |
| case GL_COMPRESSED_SIGNED_RED_RGTC1_EXT: | |
| case GL_COMPRESSED_RED_GREEN_RGTC2_EXT: | |
| case GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT: | |
| // ETC2/EAC | |
| case GL_COMPRESSED_R11_EAC: | |
| case GL_COMPRESSED_SIGNED_R11_EAC: | |
| case GL_COMPRESSED_RGB8_ETC2: | |
| case GL_COMPRESSED_SRGB8_ETC2: | |
| case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: | |
| case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: | |
| case GL_COMPRESSED_RG11_EAC: | |
| case GL_COMPRESSED_SIGNED_RG11_EAC: | |
| case GL_COMPRESSED_RGBA8_ETC2_EAC: | |
| case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: | |
| // ETC1 | |
| case GL_ETC1_RGB8_OES: | |
| // PVRTC | |
| case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG: | |
| case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG: | |
| case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG: | |
| case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: | |
| // ATC | |
| case GL_ATC_RGB_AMD: | |
| case GL_ATC_RGBA_EXPLICIT_ALPHA_AMD: | |
| case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD: | |
| return true; | |
| default: | |
| break; | |
| } | |
| return false; | |
| } | |
| Texture* CreateGLES2TextureWithLightRef(GLuint service_id, GLenum target) { | |
| Texture* texture = new Texture(service_id); | |
| texture->SetLightweightRef(); | |
| texture->SetTarget(target, 1 /*max_levels=*/); | |
| texture->set_min_filter(GL_LINEAR); | |
| texture->set_mag_filter(GL_LINEAR); | |
| texture->set_wrap_t(GL_CLAMP_TO_EDGE); | |
| texture->set_wrap_s(GL_CLAMP_TO_EDGE); | |
| return texture; | |
| } | |
| } // namespace gles2 | |
| } // namespace gpu |