junov | 0cad1f4 | 2016-01-07 21:48:51 | [diff] [blame] | 1 | // Copyright (c) 2016 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "gpu/command_buffer/service/gl_utils.h" |
| 6 | |
| 7 | #include "base/metrics/histogram.h" |
geofflang | 124fd55 | 2016-09-08 20:02:55 | [diff] [blame] | 8 | #include "gpu/command_buffer/common/capabilities.h" |
| 9 | #include "gpu/command_buffer/service/feature_info.h" |
| 10 | #include "ui/gl/gl_version_info.h" |
junov | 0cad1f4 | 2016-01-07 21:48:51 | [diff] [blame] | 11 | |
| 12 | namespace gpu { |
| 13 | namespace gles2 { |
| 14 | |
geofflang | 326c851 | 2016-11-03 15:11:28 | [diff] [blame^] | 15 | namespace { |
| 16 | const char* GetDebugSourceString(GLenum source) { |
| 17 | switch (source) { |
| 18 | case GL_DEBUG_SOURCE_API: |
| 19 | return "OpenGL"; |
| 20 | case GL_DEBUG_SOURCE_WINDOW_SYSTEM: |
| 21 | return "Window System"; |
| 22 | case GL_DEBUG_SOURCE_SHADER_COMPILER: |
| 23 | return "Shader Compiler"; |
| 24 | case GL_DEBUG_SOURCE_THIRD_PARTY: |
| 25 | return "Third Party"; |
| 26 | case GL_DEBUG_SOURCE_APPLICATION: |
| 27 | return "Application"; |
| 28 | case GL_DEBUG_SOURCE_OTHER: |
| 29 | return "Other"; |
| 30 | default: |
| 31 | return "UNKNOWN"; |
| 32 | } |
| 33 | } |
| 34 | |
| 35 | const char* GetDebugTypeString(GLenum type) { |
| 36 | switch (type) { |
| 37 | case GL_DEBUG_TYPE_ERROR: |
| 38 | return "Error"; |
| 39 | case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: |
| 40 | return "Deprecated behavior"; |
| 41 | case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: |
| 42 | return "Undefined behavior"; |
| 43 | case GL_DEBUG_TYPE_PORTABILITY: |
| 44 | return "Portability"; |
| 45 | case GL_DEBUG_TYPE_PERFORMANCE: |
| 46 | return "Performance"; |
| 47 | case GL_DEBUG_TYPE_OTHER: |
| 48 | return "Other"; |
| 49 | case GL_DEBUG_TYPE_MARKER: |
| 50 | return "Marker"; |
| 51 | default: |
| 52 | return "UNKNOWN"; |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | const char* GetDebugSeverityString(GLenum severity) { |
| 57 | switch (severity) { |
| 58 | case GL_DEBUG_SEVERITY_HIGH: |
| 59 | return "High"; |
| 60 | case GL_DEBUG_SEVERITY_MEDIUM: |
| 61 | return "Medium"; |
| 62 | case GL_DEBUG_SEVERITY_LOW: |
| 63 | return "Low"; |
| 64 | case GL_DEBUG_SEVERITY_NOTIFICATION: |
| 65 | return "Notification"; |
| 66 | default: |
| 67 | return "UNKNOWN"; |
| 68 | } |
| 69 | } |
| 70 | } |
| 71 | |
junov | 0cad1f4 | 2016-01-07 21:48:51 | [diff] [blame] | 72 | std::vector<int> GetAllGLErrors() { |
| 73 | int gl_errors[] = { |
| 74 | GL_NO_ERROR, |
| 75 | GL_INVALID_ENUM, |
| 76 | GL_INVALID_VALUE, |
| 77 | GL_INVALID_OPERATION, |
| 78 | GL_INVALID_FRAMEBUFFER_OPERATION, |
| 79 | GL_OUT_OF_MEMORY, |
| 80 | }; |
| 81 | return base::CustomHistogram::ArrayToCustomRanges(gl_errors, |
| 82 | arraysize(gl_errors)); |
| 83 | } |
| 84 | |
geofflang | 124fd55 | 2016-09-08 20:02:55 | [diff] [blame] | 85 | bool PrecisionMeetsSpecForHighpFloat(GLint rangeMin, |
| 86 | GLint rangeMax, |
| 87 | GLint precision) { |
| 88 | return (rangeMin >= 62) && (rangeMax >= 62) && (precision >= 16); |
| 89 | } |
| 90 | |
| 91 | void QueryShaderPrecisionFormat(const gl::GLVersionInfo& gl_version_info, |
| 92 | GLenum shader_type, |
| 93 | GLenum precision_type, |
| 94 | GLint* range, |
| 95 | GLint* precision) { |
| 96 | switch (precision_type) { |
| 97 | case GL_LOW_INT: |
| 98 | case GL_MEDIUM_INT: |
| 99 | case GL_HIGH_INT: |
| 100 | // These values are for a 32-bit twos-complement integer format. |
| 101 | range[0] = 31; |
| 102 | range[1] = 30; |
| 103 | *precision = 0; |
| 104 | break; |
| 105 | case GL_LOW_FLOAT: |
| 106 | case GL_MEDIUM_FLOAT: |
| 107 | case GL_HIGH_FLOAT: |
| 108 | // These values are for an IEEE single-precision floating-point format. |
| 109 | range[0] = 127; |
| 110 | range[1] = 127; |
| 111 | *precision = 23; |
| 112 | break; |
| 113 | default: |
| 114 | NOTREACHED(); |
| 115 | break; |
| 116 | } |
| 117 | |
| 118 | if (gl_version_info.is_es) { |
| 119 | // This function is sometimes defined even though it's really just |
| 120 | // a stub, so we need to set range and precision as if it weren't |
| 121 | // defined before calling it. |
| 122 | // On Mac OS with some GPUs, calling this generates a |
| 123 | // GL_INVALID_OPERATION error. Avoid calling it on non-GLES2 |
| 124 | // platforms. |
| 125 | glGetShaderPrecisionFormat(shader_type, precision_type, range, precision); |
| 126 | |
| 127 | // TODO(brianderson): Make the following official workarounds. |
| 128 | |
| 129 | // Some drivers have bugs where they report the ranges as a negative number. |
| 130 | // Taking the absolute value here shouldn't hurt because negative numbers |
| 131 | // aren't expected anyway. |
| 132 | range[0] = abs(range[0]); |
| 133 | range[1] = abs(range[1]); |
| 134 | |
| 135 | // If the driver reports a precision for highp float that isn't actually |
| 136 | // highp, don't pretend like it's supported because shader compilation will |
| 137 | // fail anyway. |
| 138 | if (precision_type == GL_HIGH_FLOAT && |
| 139 | !PrecisionMeetsSpecForHighpFloat(range[0], range[1], *precision)) { |
| 140 | range[0] = 0; |
| 141 | range[1] = 0; |
| 142 | *precision = 0; |
| 143 | } |
| 144 | } |
| 145 | } |
| 146 | |
| 147 | void PopulateNumericCapabilities(Capabilities* caps, |
| 148 | const FeatureInfo* feature_info) { |
| 149 | DCHECK(caps != nullptr); |
| 150 | |
| 151 | const gl::GLVersionInfo& version_info = feature_info->gl_version_info(); |
| 152 | caps->VisitPrecisions([&version_info]( |
| 153 | GLenum shader, GLenum type, |
| 154 | Capabilities::ShaderPrecision* shader_precision) { |
| 155 | GLint range[2] = {0, 0}; |
| 156 | GLint precision = 0; |
| 157 | QueryShaderPrecisionFormat(version_info, shader, type, range, &precision); |
| 158 | shader_precision->min_range = range[0]; |
| 159 | shader_precision->max_range = range[1]; |
| 160 | shader_precision->precision = precision; |
| 161 | }); |
| 162 | |
| 163 | glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, |
| 164 | &caps->max_combined_texture_image_units); |
| 165 | glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &caps->max_cube_map_texture_size); |
| 166 | glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, |
| 167 | &caps->max_fragment_uniform_vectors); |
| 168 | glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &caps->max_renderbuffer_size); |
| 169 | glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &caps->max_texture_image_units); |
| 170 | glGetIntegerv(GL_MAX_TEXTURE_SIZE, &caps->max_texture_size); |
| 171 | glGetIntegerv(GL_MAX_VARYING_VECTORS, &caps->max_varying_vectors); |
| 172 | glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &caps->max_vertex_attribs); |
| 173 | glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, |
| 174 | &caps->max_vertex_texture_image_units); |
| 175 | glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, |
| 176 | &caps->max_vertex_uniform_vectors); |
| 177 | glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, |
| 178 | &caps->num_compressed_texture_formats); |
| 179 | glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &caps->num_shader_binary_formats); |
| 180 | |
kainino | e20d23ac | 2016-11-03 01:03:45 | [diff] [blame] | 181 | if (feature_info->IsWebGL2OrES3Context()) { |
geofflang | 124fd55 | 2016-09-08 20:02:55 | [diff] [blame] | 182 | glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &caps->max_3d_texture_size); |
| 183 | glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &caps->max_array_texture_layers); |
| 184 | glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &caps->max_color_attachments); |
| 185 | glGetInteger64v(GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS, |
| 186 | &caps->max_combined_fragment_uniform_components); |
| 187 | glGetIntegerv(GL_MAX_COMBINED_UNIFORM_BLOCKS, |
| 188 | &caps->max_combined_uniform_blocks); |
| 189 | glGetInteger64v(GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS, |
| 190 | &caps->max_combined_vertex_uniform_components); |
| 191 | glGetIntegerv(GL_MAX_DRAW_BUFFERS, &caps->max_draw_buffers); |
| 192 | glGetInteger64v(GL_MAX_ELEMENT_INDEX, &caps->max_element_index); |
| 193 | glGetIntegerv(GL_MAX_ELEMENTS_INDICES, &caps->max_elements_indices); |
| 194 | glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &caps->max_elements_vertices); |
| 195 | glGetIntegerv(GL_MAX_FRAGMENT_INPUT_COMPONENTS, |
| 196 | &caps->max_fragment_input_components); |
| 197 | glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_BLOCKS, |
| 198 | &caps->max_fragment_uniform_blocks); |
| 199 | glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, |
| 200 | &caps->max_fragment_uniform_components); |
| 201 | glGetIntegerv(GL_MAX_PROGRAM_TEXEL_OFFSET, &caps->max_program_texel_offset); |
| 202 | glGetInteger64v(GL_MAX_SERVER_WAIT_TIMEOUT, &caps->max_server_wait_timeout); |
| 203 | glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &caps->max_texture_lod_bias); |
| 204 | glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, |
| 205 | &caps->max_transform_feedback_interleaved_components); |
| 206 | glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, |
| 207 | &caps->max_transform_feedback_separate_attribs); |
| 208 | glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS, |
| 209 | &caps->max_transform_feedback_separate_components); |
| 210 | glGetInteger64v(GL_MAX_UNIFORM_BLOCK_SIZE, &caps->max_uniform_block_size); |
| 211 | glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, |
| 212 | &caps->max_uniform_buffer_bindings); |
| 213 | glGetIntegerv(GL_MAX_VARYING_COMPONENTS, &caps->max_varying_components); |
| 214 | glGetIntegerv(GL_MAX_VERTEX_OUTPUT_COMPONENTS, |
| 215 | &caps->max_vertex_output_components); |
| 216 | glGetIntegerv(GL_MAX_VERTEX_UNIFORM_BLOCKS, |
| 217 | &caps->max_vertex_uniform_blocks); |
| 218 | glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, |
| 219 | &caps->max_vertex_uniform_components); |
| 220 | glGetIntegerv(GL_MIN_PROGRAM_TEXEL_OFFSET, &caps->min_program_texel_offset); |
| 221 | glGetIntegerv(GL_NUM_EXTENSIONS, &caps->num_extensions); |
| 222 | glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, |
| 223 | &caps->num_program_binary_formats); |
| 224 | glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, |
| 225 | &caps->uniform_buffer_offset_alignment); |
| 226 | caps->major_version = 3; |
| 227 | caps->minor_version = 0; |
| 228 | } |
| 229 | if (feature_info->feature_flags().multisampled_render_to_texture || |
| 230 | feature_info->feature_flags().chromium_framebuffer_multisample || |
kainino | e20d23ac | 2016-11-03 01:03:45 | [diff] [blame] | 231 | feature_info->IsWebGL2OrES3Context()) { |
geofflang | 124fd55 | 2016-09-08 20:02:55 | [diff] [blame] | 232 | glGetIntegerv(GL_MAX_SAMPLES, &caps->max_samples); |
| 233 | } |
| 234 | } |
| 235 | |
geofflang | 851a481 | 2016-09-14 19:20:29 | [diff] [blame] | 236 | bool CheckUniqueAndNonNullIds(GLsizei n, const GLuint* client_ids) { |
| 237 | if (n <= 0) |
| 238 | return true; |
| 239 | std::unordered_set<uint32_t> unique_ids(client_ids, client_ids + n); |
| 240 | return (unique_ids.size() == static_cast<size_t>(n)) && |
| 241 | (unique_ids.find(0) == unique_ids.end()); |
| 242 | } |
| 243 | |
geofflang | 326c851 | 2016-11-03 15:11:28 | [diff] [blame^] | 244 | void APIENTRY LogGLDebugMessage(GLenum source, |
| 245 | GLenum type, |
| 246 | GLuint id, |
| 247 | GLenum severity, |
| 248 | GLsizei length, |
| 249 | const GLchar* message, |
| 250 | GLvoid* user_param) { |
| 251 | LOG(ERROR) << "GL Driver Message (" << GetDebugSourceString(source) << ", " |
| 252 | << GetDebugTypeString(type) << ", " << id << ", " |
| 253 | << GetDebugSeverityString(severity) << "): " << message; |
| 254 | } |
| 255 | |
| 256 | void InitializeGLDebugLogging() { |
| 257 | glEnable(GL_DEBUG_OUTPUT); |
| 258 | glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); |
| 259 | |
| 260 | // Enable logging of medium and high severity messages |
| 261 | glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH, 0, |
| 262 | nullptr, GL_TRUE); |
| 263 | glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_MEDIUM, 0, |
| 264 | nullptr, GL_TRUE); |
| 265 | glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW, 0, |
| 266 | nullptr, GL_FALSE); |
| 267 | glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, |
| 268 | GL_DEBUG_SEVERITY_NOTIFICATION, 0, nullptr, GL_FALSE); |
| 269 | |
| 270 | glDebugMessageCallback(&LogGLDebugMessage, nullptr); |
| 271 | } |
| 272 | |
junov | 0cad1f4 | 2016-01-07 21:48:51 | [diff] [blame] | 273 | } // namespace gles2 |
| 274 | } // namespace gpu |