| // Copyright 2012 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/context_group.h" | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| #include <algorithm> | |
| #include <memory> | |
| #include <string> | |
| #include <vector> | |
| #include "base/command_line.h" | |
| #include "base/memory/raw_ptr.h" | |
| #include "build/build_config.h" | |
| #include "gpu/command_buffer/service/buffer_manager.h" | |
| #include "gpu/command_buffer/service/decoder_context.h" | |
| #include "gpu/command_buffer/service/framebuffer_manager.h" | |
| #include "gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h" | |
| #include "gpu/command_buffer/service/program_manager.h" | |
| #include "gpu/command_buffer/service/renderbuffer_manager.h" | |
| #include "gpu/command_buffer/service/sampler_manager.h" | |
| #include "gpu/command_buffer/service/shader_manager.h" | |
| #include "gpu/command_buffer/service/shared_image/shared_image_factory.h" | |
| #include "gpu/command_buffer/service/texture_manager.h" | |
| #include "gpu/config/gpu_preferences.h" | |
| #include "ui/gl/gl_bindings.h" | |
| #include "ui/gl/gl_version_info.h" | |
| #include "ui/gl/progress_reporter.h" | |
| namespace gpu { | |
| namespace gles2 { | |
| namespace { | |
| void GetIntegerv(GLenum pname, uint32_t* var) { | |
| GLint value = 0; | |
| glGetIntegerv(pname, &value); | |
| *var = value; | |
| } | |
| } // namespace anonymous | |
| DisallowedFeatures GetDisallowedFeatures(ContextType context_type) { | |
| DisallowedFeatures adjusted_disallowed_features; | |
| if (context_type == CONTEXT_TYPE_WEBGL1) { | |
| adjusted_disallowed_features.npot_support = true; | |
| } | |
| if (context_type == CONTEXT_TYPE_WEBGL1 || | |
| context_type == CONTEXT_TYPE_WEBGL2) { | |
| adjusted_disallowed_features.chromium_color_buffer_float_rgba = true; | |
| adjusted_disallowed_features.chromium_color_buffer_float_rgb = true; | |
| adjusted_disallowed_features.ext_color_buffer_float = true; | |
| adjusted_disallowed_features.oes_texture_float_linear = true; | |
| adjusted_disallowed_features.ext_color_buffer_half_float = true; | |
| adjusted_disallowed_features.oes_texture_half_float_linear = true; | |
| adjusted_disallowed_features.ext_texture_filter_anisotropic = true; | |
| adjusted_disallowed_features.ext_float_blend = true; | |
| adjusted_disallowed_features.oes_fbo_render_mipmap = true; | |
| adjusted_disallowed_features.oes_draw_buffers_indexed = true; | |
| adjusted_disallowed_features.webgl_compressed_texture_etc = true; | |
| adjusted_disallowed_features.webgl_compressed_texture_etc1 = true; | |
| } | |
| return adjusted_disallowed_features; | |
| } | |
| ContextGroup::ContextGroup( | |
| const GpuPreferences& gpu_preferences, | |
| scoped_refptr<MemoryTracker> memory_tracker, | |
| ShaderTranslatorCache* shader_translator_cache, | |
| FramebufferCompletenessCache* framebuffer_completeness_cache, | |
| const scoped_refptr<FeatureInfo>& feature_info, | |
| gl::ProgressReporter* progress_reporter, | |
| const GpuFeatureInfo& gpu_feature_info, | |
| SharedImageManager* shared_image_manager) | |
| : gpu_preferences_(gpu_preferences), | |
| memory_tracker_(std::move(memory_tracker)), | |
| shader_translator_cache_(shader_translator_cache), | |
| #if BUILDFLAG(IS_MAC) | |
| // Framebuffer completeness is not cacheable on OS X because of dynamic | |
| // graphics switching. | |
| // http://crbug.com/180876 | |
| // TODO(tobiasjs): determine whether GPU switching is possible | |
| // programmatically, rather than just hardcoding this behaviour | |
| // for OS X. | |
| framebuffer_completeness_cache_(nullptr), | |
| #else | |
| framebuffer_completeness_cache_(framebuffer_completeness_cache), | |
| #endif | |
| enforce_gl_minimums_(gpu_preferences_.enforce_gl_minimums), | |
| max_vertex_attribs_(0u), | |
| max_texture_units_(0u), | |
| max_texture_image_units_(0u), | |
| max_vertex_texture_image_units_(0u), | |
| max_fragment_uniform_vectors_(0u), | |
| max_varying_vectors_(0u), | |
| max_vertex_uniform_vectors_(0u), | |
| max_color_attachments_(1u), | |
| max_draw_buffers_(1u), | |
| max_dual_source_draw_buffers_(0u), | |
| max_vertex_output_components_(0u), | |
| max_fragment_input_components_(0u), | |
| min_program_texel_offset_(0), | |
| max_program_texel_offset_(0), | |
| max_transform_feedback_separate_attribs_(0u), | |
| max_uniform_buffer_bindings_(0u), | |
| uniform_buffer_offset_alignment_(1u), | |
| program_cache_(nullptr), | |
| feature_info_(feature_info), | |
| use_passthrough_cmd_decoder_(false), | |
| passthrough_resources_(new PassthroughResources), | |
| progress_reporter_(progress_reporter), | |
| gpu_feature_info_(gpu_feature_info), | |
| shared_image_representation_factory_( | |
| std::make_unique<SharedImageRepresentationFactory>( | |
| shared_image_manager, | |
| memory_tracker_)), | |
| shared_image_manager_(shared_image_manager) { | |
| DCHECK(feature_info_); | |
| use_passthrough_cmd_decoder_ = gpu_preferences_.use_passthrough_cmd_decoder; | |
| } | |
| gpu::ContextResult ContextGroup::Initialize(DecoderContext* decoder, | |
| ContextType context_type) { | |
| return InitializeWithCompleteFramebufferForWorkarounds(decoder, context_type, | |
| 0); | |
| } | |
| gpu::ContextResult | |
| ContextGroup::InitializeWithCompleteFramebufferForWorkarounds( | |
| DecoderContext* decoder, | |
| ContextType context_type, | |
| uint32_t complete_fbo_for_workarounds) { | |
| switch (context_type) { | |
| case CONTEXT_TYPE_WEBGL1: | |
| if (kGpuFeatureStatusBlocklisted == | |
| gpu_feature_info_.status_values[GPU_FEATURE_TYPE_ACCELERATED_WEBGL]) { | |
| LOG(ERROR) << "ContextResult::kFatalFailure: WebGL1 blocklisted"; | |
| return gpu::ContextResult::kFatalFailure; | |
| } | |
| break; | |
| case CONTEXT_TYPE_WEBGL2: | |
| if (kGpuFeatureStatusBlocklisted == | |
| gpu_feature_info_ | |
| .status_values[GPU_FEATURE_TYPE_ACCELERATED_WEBGL2]) { | |
| LOG(ERROR) << "ContextResult::kFatalFailure: WebGL2 blocklisted"; | |
| return gpu::ContextResult::kFatalFailure; | |
| } | |
| break; | |
| default: | |
| break; | |
| } | |
| if (HaveContexts()) { | |
| if (context_type != feature_info_->context_type()) { | |
| LOG(ERROR) << "ContextResult::kFatalFailure: the type of " | |
| "the context does not fit with the group."; | |
| return gpu::ContextResult::kFatalFailure; | |
| } | |
| // If we've already initialized the group just add the context. | |
| decoders_.push_back(decoder->AsWeakPtr()); | |
| return gpu::ContextResult::kSuccess; | |
| } | |
| DisallowedFeatures adjusted_disallowed_features = | |
| GetDisallowedFeatures(context_type); | |
| feature_info_->InitializeWithCompleteFramebufferForWorkarounds( | |
| context_type, use_passthrough_cmd_decoder_, adjusted_disallowed_features, | |
| complete_fbo_for_workarounds); | |
| // Fail early if ES3 is requested and driver does not support it. | |
| if ((context_type == CONTEXT_TYPE_WEBGL2 || | |
| context_type == CONTEXT_TYPE_OPENGLES3) && | |
| !feature_info_->IsES3Capable()) { | |
| LOG(ERROR) << "ContextResult::kFatalFailure: " | |
| << "ES3 is blocklisted/disabled/unsupported by driver."; | |
| return gpu::ContextResult::kFatalFailure; | |
| } | |
| const GLint kMinRenderbufferSize = 512; // GL says 1 pixel! | |
| GLint max_renderbuffer_size = 0; | |
| if (!QueryGLFeature( | |
| GL_MAX_RENDERBUFFER_SIZE, kMinRenderbufferSize, | |
| &max_renderbuffer_size)) { | |
| bool was_lost = decoder->CheckResetStatus(); | |
| LOG(ERROR) << (was_lost ? "ContextResult::kTransientFailure: " | |
| : "ContextResult::kFatalFailure: ") | |
| << "maximum renderbuffer size too small (" | |
| << max_renderbuffer_size << ", should be " | |
| << kMinRenderbufferSize << ")."; | |
| return was_lost ? gpu::ContextResult::kTransientFailure | |
| : gpu::ContextResult::kFatalFailure; | |
| } | |
| GLint max_samples = 0; | |
| if (feature_info_->feature_flags().chromium_framebuffer_multisample || | |
| feature_info_->feature_flags().multisampled_render_to_texture) { | |
| if (feature_info_->feature_flags() | |
| .use_img_for_multisampled_render_to_texture) { | |
| glGetIntegerv(GL_MAX_SAMPLES_IMG, &max_samples); | |
| } else { | |
| glGetIntegerv(GL_MAX_SAMPLES, &max_samples); | |
| } | |
| } | |
| if (context_type == CONTEXT_TYPE_OPENGLES3 || | |
| context_type == CONTEXT_TYPE_WEBGL2 || | |
| feature_info_->feature_flags().ext_draw_buffers) { | |
| GetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &max_color_attachments_); | |
| if (max_color_attachments_ < 1) | |
| max_color_attachments_ = 1; | |
| if (max_color_attachments_ > 16) | |
| max_color_attachments_ = 16; | |
| GetIntegerv(GL_MAX_DRAW_BUFFERS, &max_draw_buffers_); | |
| if (max_draw_buffers_ < 1) | |
| max_draw_buffers_ = 1; | |
| if (max_draw_buffers_ > 16) | |
| max_draw_buffers_ = 16; | |
| } | |
| if (feature_info_->feature_flags().ext_blend_func_extended) { | |
| GetIntegerv(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT, | |
| &max_dual_source_draw_buffers_); | |
| DCHECK(max_dual_source_draw_buffers_ >= 1); | |
| } | |
| if (feature_info_->gl_version_info().IsAtLeastGLES(3, 0)) { | |
| const GLint kMinTransformFeedbackSeparateAttribs = 4; | |
| if (!QueryGLFeatureU(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, | |
| kMinTransformFeedbackSeparateAttribs, | |
| &max_transform_feedback_separate_attribs_)) { | |
| bool was_lost = decoder->CheckResetStatus(); | |
| LOG(ERROR) << (was_lost ? "ContextResult::kTransientFailure: " | |
| : "ContextResult::kFatalFailure: ") | |
| << "maximum transform feedback separate attribs is too small (" | |
| << max_transform_feedback_separate_attribs_ << ", should be " | |
| << kMinTransformFeedbackSeparateAttribs << ")."; | |
| return was_lost ? gpu::ContextResult::kTransientFailure | |
| : gpu::ContextResult::kFatalFailure; | |
| } | |
| const GLint kMinUniformBufferBindings = 24; | |
| if (!QueryGLFeatureU(GL_MAX_UNIFORM_BUFFER_BINDINGS, | |
| kMinUniformBufferBindings, | |
| &max_uniform_buffer_bindings_)) { | |
| bool was_lost = decoder->CheckResetStatus(); | |
| LOG(ERROR) << (was_lost ? "ContextResult::kTransientFailure: " | |
| : "ContextResult::kFatalFailure: ") | |
| << "maximum uniform buffer bindings is too small (" | |
| << max_uniform_buffer_bindings_ << ", should be " | |
| << kMinUniformBufferBindings << ")."; | |
| return was_lost ? gpu::ContextResult::kTransientFailure | |
| : gpu::ContextResult::kFatalFailure; | |
| } | |
| // TODO(zmo): Should we check max UNIFORM_BUFFER_OFFSET_ALIGNMENT is 256? | |
| GetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, | |
| &uniform_buffer_offset_alignment_); | |
| } | |
| // Managers are not used by the passthrough command decoder. Save memory by | |
| // not allocating them. | |
| if (!use_passthrough_cmd_decoder_) { | |
| buffer_manager_ = | |
| std::make_unique<BufferManager>(memory_tracker_, feature_info_.get()); | |
| renderbuffer_manager_ = std::make_unique<RenderbufferManager>( | |
| memory_tracker_, max_renderbuffer_size, max_samples, | |
| feature_info_.get()); | |
| shader_manager_ = std::make_unique<ShaderManager>(progress_reporter_); | |
| sampler_manager_ = std::make_unique<SamplerManager>(feature_info_.get()); | |
| } | |
| // Lookup GL things we need to know. | |
| const GLint kGLES2RequiredMinimumVertexAttribs = 8u; | |
| if (!QueryGLFeatureU( | |
| GL_MAX_VERTEX_ATTRIBS, kGLES2RequiredMinimumVertexAttribs, | |
| &max_vertex_attribs_)) { | |
| bool was_lost = decoder->CheckResetStatus(); | |
| LOG(ERROR) << (was_lost ? "ContextResult::kTransientFailure: " | |
| : "ContextResult::kFatalFailure: ") | |
| << "too few vertex attributes supported (" << max_vertex_attribs_ | |
| << ", should be " << kGLES2RequiredMinimumVertexAttribs << ")."; | |
| return was_lost ? gpu::ContextResult::kTransientFailure | |
| : gpu::ContextResult::kFatalFailure; | |
| } | |
| const GLuint kGLES2RequiredMinimumTextureUnits = 8u; | |
| if (!QueryGLFeatureU( | |
| GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, kGLES2RequiredMinimumTextureUnits, | |
| &max_texture_units_)) { | |
| bool was_lost = decoder->CheckResetStatus(); | |
| LOG(ERROR) << (was_lost ? "ContextResult::kTransientFailure: " | |
| : "ContextResult::kFatalFailure: ") | |
| << "too few texture units supported (" << max_texture_units_ | |
| << ", should be " << kGLES2RequiredMinimumTextureUnits << ")."; | |
| return was_lost ? gpu::ContextResult::kTransientFailure | |
| : gpu::ContextResult::kFatalFailure; | |
| } | |
| GLint max_texture_size = 0; | |
| GLint max_cube_map_texture_size = 0; | |
| GLint max_rectangle_texture_size = 0; | |
| GLint max_3d_texture_size = 0; | |
| GLint max_array_texture_layers = 0; | |
| const GLint kMinTextureSize = 2048; // GL actually says 64!?!? | |
| const GLint kMinCubeMapSize = 256; // GL actually says 16!?!? | |
| const GLint kMinRectangleTextureSize = 64; | |
| const GLint kMin3DTextureSize = 256; | |
| const GLint kMinArrayTextureLayers = 256; | |
| if (!QueryGLFeature(GL_MAX_TEXTURE_SIZE, kMinTextureSize, | |
| &max_texture_size)) { | |
| bool was_lost = decoder->CheckResetStatus(); | |
| LOG(ERROR) << (was_lost ? "ContextResult::kTransientFailure: " | |
| : "ContextResult::kFatalFailure: ") | |
| << "maximum 2d texture size is too small (" << max_texture_size | |
| << ", should be " << kMinTextureSize << ")."; | |
| return was_lost ? gpu::ContextResult::kTransientFailure | |
| : gpu::ContextResult::kFatalFailure; | |
| } | |
| if (!QueryGLFeature(GL_MAX_CUBE_MAP_TEXTURE_SIZE, kMinCubeMapSize, | |
| &max_cube_map_texture_size)) { | |
| bool was_lost = decoder->CheckResetStatus(); | |
| LOG(ERROR) << (was_lost ? "ContextResult::kTransientFailure: " | |
| : "ContextResult::kFatalFailure: ") | |
| << "maximum cube texture size is too small (" | |
| << max_cube_map_texture_size << ", should be " << kMinCubeMapSize | |
| << ")."; | |
| return was_lost ? gpu::ContextResult::kTransientFailure | |
| : gpu::ContextResult::kFatalFailure; | |
| } | |
| if (feature_info_->gl_version_info().IsAtLeastGLES(3, 0) && | |
| !QueryGLFeature(GL_MAX_3D_TEXTURE_SIZE, kMin3DTextureSize, | |
| &max_3d_texture_size)) { | |
| bool was_lost = decoder->CheckResetStatus(); | |
| LOG(ERROR) << (was_lost ? "ContextResult::kTransientFailure: " | |
| : "ContextResult::kFatalFailure: ") | |
| << "maximum 3d texture size is too small (" | |
| << max_3d_texture_size << ", should be " << kMin3DTextureSize | |
| << ")."; | |
| return was_lost ? gpu::ContextResult::kTransientFailure | |
| : gpu::ContextResult::kFatalFailure; | |
| } | |
| if (feature_info_->gl_version_info().IsAtLeastGLES(3, 0) && | |
| !QueryGLFeature(GL_MAX_ARRAY_TEXTURE_LAYERS, kMinArrayTextureLayers, | |
| &max_array_texture_layers)) { | |
| bool was_lost = decoder->CheckResetStatus(); | |
| LOG(ERROR) << (was_lost ? "ContextResult::kTransientFailure: " | |
| : "ContextResult::kFatalFailure: ") | |
| << "maximum array texture layers is too small (" | |
| << max_array_texture_layers << ", should be " | |
| << kMinArrayTextureLayers << ")."; | |
| return was_lost ? gpu::ContextResult::kTransientFailure | |
| : gpu::ContextResult::kFatalFailure; | |
| } | |
| if (feature_info_->feature_flags().arb_texture_rectangle && | |
| !QueryGLFeature(GL_MAX_RECTANGLE_TEXTURE_SIZE_ANGLE, | |
| kMinRectangleTextureSize, &max_rectangle_texture_size)) { | |
| bool was_lost = decoder->CheckResetStatus(); | |
| LOG(ERROR) << (was_lost ? "ContextResult::kTransientFailure: " | |
| : "ContextResult::kFatalFailure: ") | |
| << "maximum rectangle texture size is too small (" | |
| << max_rectangle_texture_size << ", should be " | |
| << kMinRectangleTextureSize << ")."; | |
| return was_lost ? gpu::ContextResult::kTransientFailure | |
| : gpu::ContextResult::kFatalFailure; | |
| } | |
| if (feature_info_->workarounds().webgl_or_caps_max_texture_size && | |
| feature_info_->IsWebGLContext()) { | |
| max_texture_size = | |
| std::min(max_texture_size, | |
| feature_info_->workarounds().webgl_or_caps_max_texture_size); | |
| max_rectangle_texture_size = | |
| std::min(max_rectangle_texture_size, | |
| feature_info_->workarounds().webgl_or_caps_max_texture_size); | |
| max_cube_map_texture_size = | |
| std::min(max_cube_map_texture_size, | |
| feature_info_->workarounds().webgl_or_caps_max_texture_size); | |
| } | |
| if (feature_info_->workarounds().max_3d_array_texture_size) { | |
| max_3d_texture_size = | |
| std::min(max_3d_texture_size, | |
| feature_info_->workarounds().max_3d_array_texture_size); | |
| max_array_texture_layers = | |
| std::min(max_array_texture_layers, | |
| feature_info_->workarounds().max_3d_array_texture_size); | |
| } | |
| // Managers are not used by the passthrough command decoder. Save memory by | |
| // not allocating them. | |
| if (!use_passthrough_cmd_decoder_) { | |
| texture_manager_ = std::make_unique<TextureManager>( | |
| memory_tracker_, feature_info_.get(), max_texture_size, | |
| max_cube_map_texture_size, max_rectangle_texture_size, | |
| max_3d_texture_size, max_array_texture_layers, | |
| /*use_default_textures=*/false, progress_reporter_); | |
| } | |
| const GLint kMinTextureImageUnits = 8; | |
| const GLint kMinVertexTextureImageUnits = 0; | |
| if (!QueryGLFeatureU(GL_MAX_TEXTURE_IMAGE_UNITS, kMinTextureImageUnits, | |
| &max_texture_image_units_)) { | |
| bool was_lost = decoder->CheckResetStatus(); | |
| LOG(ERROR) << (was_lost ? "ContextResult::kTransientFailure: " | |
| : "ContextResult::kFatalFailure: ") | |
| << "too few texture image units supported (" | |
| << max_texture_image_units_ << ", should be " | |
| << kMinTextureImageUnits << ")."; | |
| return was_lost ? gpu::ContextResult::kTransientFailure | |
| : gpu::ContextResult::kFatalFailure; | |
| } | |
| if (feature_info_->workarounds().max_texture_image_units_13) { | |
| max_texture_image_units_ = std::min(max_texture_image_units_, 13u); | |
| } | |
| if (!QueryGLFeatureU(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, | |
| kMinVertexTextureImageUnits, | |
| &max_vertex_texture_image_units_)) { | |
| bool was_lost = decoder->CheckResetStatus(); | |
| LOG(ERROR) << (was_lost ? "ContextResult::kTransientFailure: " | |
| : "ContextResult::kFatalFailure: ") | |
| << "too few vertex texture image units supported (" | |
| << max_vertex_texture_image_units_ << ", should be " | |
| << kMinTextureImageUnits << ")."; | |
| return was_lost ? gpu::ContextResult::kTransientFailure | |
| : gpu::ContextResult::kFatalFailure; | |
| } | |
| GetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &max_fragment_uniform_vectors_); | |
| GetIntegerv(GL_MAX_VARYING_VECTORS, &max_varying_vectors_); | |
| GetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &max_vertex_uniform_vectors_); | |
| const GLint kMinFragmentUniformVectors = 16; | |
| const GLint kMinVaryingVectors = 8; | |
| const GLint kMinVertexUniformVectors = 128; | |
| if (!CheckGLFeatureU( | |
| kMinFragmentUniformVectors, &max_fragment_uniform_vectors_) || | |
| !CheckGLFeatureU(kMinVaryingVectors, &max_varying_vectors_) || | |
| !CheckGLFeatureU( | |
| kMinVertexUniformVectors, &max_vertex_uniform_vectors_)) { | |
| bool was_lost = decoder->CheckResetStatus(); | |
| LOG(ERROR) << (was_lost ? "ContextResult::kTransientFailure: " | |
| : "ContextResult::kFatalFailure: ") | |
| << "too few uniforms or varyings supported."; | |
| return was_lost ? gpu::ContextResult::kTransientFailure | |
| : gpu::ContextResult::kFatalFailure; | |
| } | |
| if (context_type != CONTEXT_TYPE_WEBGL1 && | |
| context_type != CONTEXT_TYPE_OPENGLES2) { | |
| const GLuint kMinVertexOutputComponents = 64; | |
| const GLuint kMinFragmentInputComponents = 60; | |
| const GLint kMin_MaxProgramTexelOffset = 7; | |
| const GLint kMax_MinProgramTexelOffset = -8; | |
| if (!QueryGLFeatureU(GL_MAX_VERTEX_OUTPUT_COMPONENTS, | |
| kMinVertexOutputComponents, | |
| &max_vertex_output_components_)) { | |
| bool was_lost = decoder->CheckResetStatus(); | |
| LOG(ERROR) << (was_lost ? "ContextResult::kTransientFailure: " | |
| : "ContextResult::kFatalFailure: ") | |
| << "maximum vertex output components is too small (" | |
| << max_vertex_output_components_ << ", should be " | |
| << kMinVertexOutputComponents << ")."; | |
| return was_lost ? gpu::ContextResult::kTransientFailure | |
| : gpu::ContextResult::kFatalFailure; | |
| } | |
| if (!QueryGLFeatureU(GL_MAX_FRAGMENT_INPUT_COMPONENTS, | |
| kMinFragmentInputComponents, | |
| &max_fragment_input_components_)) { | |
| bool was_lost = decoder->CheckResetStatus(); | |
| LOG(ERROR) << (was_lost ? "ContextResult::kTransientFailure: " | |
| : "ContextResult::kFatalFailure: ") | |
| << "maximum fragment input components is too small (" | |
| << max_fragment_input_components_ << ", should be " | |
| << kMinFragmentInputComponents << ")."; | |
| return was_lost ? gpu::ContextResult::kTransientFailure | |
| : gpu::ContextResult::kFatalFailure; | |
| } | |
| if (!QueryGLFeature(GL_MAX_PROGRAM_TEXEL_OFFSET, kMin_MaxProgramTexelOffset, | |
| &max_program_texel_offset_)) { | |
| bool was_lost = decoder->CheckResetStatus(); | |
| LOG(ERROR) << (was_lost ? "ContextResult::kTransientFailure: " | |
| : "ContextResult::kFatalFailure: ") | |
| << "maximum program texel offset is too small (" | |
| << max_program_texel_offset_ << ", should be " | |
| << kMin_MaxProgramTexelOffset << ")."; | |
| return was_lost ? gpu::ContextResult::kTransientFailure | |
| : gpu::ContextResult::kFatalFailure; | |
| } | |
| glGetIntegerv(GL_MIN_PROGRAM_TEXEL_OFFSET, &min_program_texel_offset_); | |
| if (enforce_gl_minimums_) { | |
| min_program_texel_offset_ = | |
| std::max(min_program_texel_offset_, kMax_MinProgramTexelOffset); | |
| } | |
| if (min_program_texel_offset_ > kMax_MinProgramTexelOffset) { | |
| bool was_lost = decoder->CheckResetStatus(); | |
| LOG(ERROR) << (was_lost ? "ContextResult::kTransientFailure: " | |
| : "ContextResult::kFatalFailure: ") | |
| << "minimum program texel offset is too big (" | |
| << min_program_texel_offset_ << ", should be " | |
| << kMax_MinProgramTexelOffset << ")."; | |
| return was_lost ? gpu::ContextResult::kTransientFailure | |
| : gpu::ContextResult::kFatalFailure; | |
| } | |
| const GLint kES3MinCubeMapSize = 2048; | |
| if (max_cube_map_texture_size < kES3MinCubeMapSize) { | |
| bool was_lost = decoder->CheckResetStatus(); | |
| LOG(ERROR) << (was_lost ? "ContextResult::kTransientFailure: " | |
| : "ContextResult::kFatalFailure: ") | |
| << "maximum cube texture size is too small (" | |
| << max_cube_map_texture_size << ", should be " | |
| << kES3MinCubeMapSize << ")."; | |
| return was_lost ? gpu::ContextResult::kTransientFailure | |
| : gpu::ContextResult::kFatalFailure; | |
| } | |
| } | |
| // Managers are not used by the passthrough command decoder. Save memory by | |
| // not allocating them. | |
| if (!use_passthrough_cmd_decoder_) { | |
| program_manager_ = std::make_unique<ProgramManager>( | |
| program_cache_, max_varying_vectors_, max_draw_buffers_, | |
| max_dual_source_draw_buffers_, max_vertex_attribs_, gpu_preferences_, | |
| feature_info_.get(), progress_reporter_); | |
| texture_manager_->Initialize(); | |
| } | |
| decoders_.push_back(decoder->AsWeakPtr()); | |
| return gpu::ContextResult::kSuccess; | |
| } | |
| namespace { | |
| bool IsNull(const base::WeakPtr<DecoderContext>& decoder) { | |
| return !decoder; | |
| } | |
| template <typename T> | |
| class WeakPtrEquals { | |
| public: | |
| explicit WeakPtrEquals(T* t) : t_(t) {} | |
| bool operator()(const base::WeakPtr<T>& t) { | |
| return t.get() == t_; | |
| } | |
| private: | |
| const raw_ptr<T> t_; | |
| }; | |
| } // namespace anonymous | |
| bool ContextGroup::HaveContexts() { | |
| std::erase_if(decoders_, IsNull); | |
| return !decoders_.empty(); | |
| } | |
| void ContextGroup::ReportProgress() { | |
| if (progress_reporter_) | |
| progress_reporter_->ReportProgress(); | |
| } | |
| void ContextGroup::Destroy(DecoderContext* decoder, bool have_context) { | |
| std::erase_if(decoders_, WeakPtrEquals<DecoderContext>(decoder)); | |
| // If we still have contexts do nothing. | |
| if (HaveContexts()) { | |
| return; | |
| } | |
| if (buffer_manager_ != nullptr) { | |
| if (!have_context) { | |
| buffer_manager_->MarkContextLost(); | |
| } | |
| buffer_manager_->Destroy(); | |
| buffer_manager_.reset(); | |
| ReportProgress(); | |
| } | |
| if (renderbuffer_manager_ != nullptr) { | |
| renderbuffer_manager_->Destroy(have_context); | |
| renderbuffer_manager_.reset(); | |
| ReportProgress(); | |
| } | |
| if (texture_manager_ != nullptr) { | |
| if (!have_context) | |
| texture_manager_->MarkContextLost(); | |
| texture_manager_->Destroy(); | |
| texture_manager_.reset(); | |
| ReportProgress(); | |
| } | |
| if (program_manager_ != nullptr) { | |
| program_manager_->Destroy(have_context); | |
| program_manager_.reset(); | |
| ReportProgress(); | |
| } | |
| if (shader_manager_ != nullptr) { | |
| shader_manager_->Destroy(have_context); | |
| shader_manager_.reset(); | |
| ReportProgress(); | |
| } | |
| if (sampler_manager_ != nullptr) { | |
| sampler_manager_->Destroy(have_context); | |
| sampler_manager_.reset(); | |
| ReportProgress(); | |
| } | |
| if (passthrough_resources_) { | |
| gl::GLApi* api = have_context ? gl::g_current_gl_context : nullptr; | |
| passthrough_resources_->Destroy(api, progress_reporter_); | |
| passthrough_resources_.reset(); | |
| ReportProgress(); | |
| } | |
| } | |
| uint32_t ContextGroup::GetMemRepresented() const { | |
| uint32_t total = 0; | |
| if (buffer_manager_.get()) | |
| total += buffer_manager_->mem_represented(); | |
| if (renderbuffer_manager_.get()) | |
| total += renderbuffer_manager_->mem_represented(); | |
| if (texture_manager_.get()) | |
| total += texture_manager_->mem_represented(); | |
| return total; | |
| } | |
| void ContextGroup::LoseContexts(error::ContextLostReason reason) { | |
| for (size_t ii = 0; ii < decoders_.size(); ++ii) { | |
| if (decoders_[ii].get()) { | |
| decoders_[ii]->MarkContextLost(reason); | |
| } | |
| } | |
| if (buffer_manager_ != nullptr) { | |
| buffer_manager_->MarkContextLost(); | |
| } | |
| } | |
| ContextGroup::~ContextGroup() { | |
| CHECK(!HaveContexts()); | |
| } | |
| bool ContextGroup::CheckGLFeature(GLint min_required, GLint* v) { | |
| GLint value = *v; | |
| if (enforce_gl_minimums_) { | |
| value = std::min(min_required, value); | |
| } | |
| *v = value; | |
| return value >= min_required; | |
| } | |
| bool ContextGroup::CheckGLFeatureU(GLint min_required, uint32_t* v) { | |
| GLint value = *v; | |
| if (enforce_gl_minimums_) { | |
| value = std::min(min_required, value); | |
| } | |
| *v = value; | |
| return value >= min_required; | |
| } | |
| bool ContextGroup::QueryGLFeature( | |
| GLenum pname, GLint min_required, GLint* v) { | |
| GLint value = 0; | |
| glGetIntegerv(pname, &value); | |
| *v = value; | |
| return CheckGLFeature(min_required, v); | |
| } | |
| bool ContextGroup::QueryGLFeatureU(GLenum pname, | |
| GLint min_required, | |
| uint32_t* v) { | |
| uint32_t value = 0; | |
| GetIntegerv(pname, &value); | |
| bool result = CheckGLFeatureU(min_required, &value); | |
| *v = value; | |
| return result; | |
| } | |
| bool ContextGroup::GetBufferServiceId( | |
| GLuint client_id, GLuint* service_id) const { | |
| Buffer* buffer = buffer_manager_->GetBuffer(client_id); | |
| if (!buffer) | |
| return false; | |
| *service_id = buffer->service_id(); | |
| return true; | |
| } | |
| } // namespace gles2 | |
| } // namespace gpu |