| // Copyright 2018 The Chromium Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #ifndef GPU_COMMAND_BUFFER_SERVICE_SHARED_CONTEXT_STATE_H_ | |
| #define GPU_COMMAND_BUFFER_SERVICE_SHARED_CONTEXT_STATE_H_ | |
| #include <memory> | |
| #include <optional> | |
| #include <vector> | |
| #include "base/containers/lru_cache.h" | |
| #include "base/gtest_prod_util.h" | |
| #include "base/memory/memory_pressure_listener.h" | |
| #include "base/memory/raw_ptr.h" | |
| #include "base/memory/ref_counted.h" | |
| #include "base/memory/weak_ptr.h" | |
| #include "base/memory_coordinator/memory_limit.h" | |
| #include "base/observer_list.h" | |
| #include "base/threading/thread_checker.h" | |
| #include "base/time/time.h" | |
| #include "base/timer/timer.h" | |
| #include "base/trace_event/memory_dump_provider.h" | |
| #include "build/build_config.h" | |
| #include "gpu/command_buffer/common/constants.h" | |
| #include "gpu/command_buffer/common/gl2_types.h" | |
| #include "gpu/command_buffer/common/skia_utils.h" | |
| #include "gpu/command_buffer/service/gl_context_virtual_delegate.h" | |
| #include "gpu/command_buffer/service/gpu_persistent_cache.h" | |
| #include "gpu/command_buffer/service/gr_shader_cache.h" | |
| #include "gpu/command_buffer/service/memory_tracking.h" | |
| #include "gpu/command_buffer/service/shared_image/shared_image_format_service_utils.h" | |
| #include "gpu/command_buffer/service/shared_image/shared_image_representation.h" | |
| #include "gpu/config/gpu_preferences.h" | |
| #include "gpu/gpu_gles2_export.h" | |
| #include "gpu/ipc/common/command_buffer_id.h" | |
| #include "gpu/ipc/common/gpu_peak_memory.h" | |
| #include "gpu/vulkan/buildflags.h" | |
| #include "skia/buildflags.h" | |
| #include "third_party/skia/include/core/SkSurface.h" | |
| #include "third_party/skia/include/gpu/ganesh/GrDirectContext.h" | |
| #include "ui/gl/progress_reporter.h" | |
| #if BUILDFLAG(IS_WIN) | |
| #include <d3d11.h> | |
| #include <d3d12.h> | |
| #include <wrl/client.h> | |
| #endif | |
| namespace gl { | |
| class GLContext; | |
| class GLDisplay; | |
| class GLShareGroup; | |
| class GLSurface; | |
| } // namespace gl | |
| namespace skgpu::graphite { | |
| class PrecompileContext; | |
| class Recorder; | |
| } // namespace skgpu::graphite | |
| namespace gpu { | |
| class DawnContextProvider; | |
| class ExternalSemaphorePool; | |
| class GpuDriverBugWorkarounds; | |
| class GpuProcessShmCount; | |
| class ServiceTransferCache; | |
| class GraphiteSharedContext; | |
| class VulkanContextProvider; | |
| struct GpuFeatureInfo; | |
| namespace gles2 { | |
| class FeatureInfo; | |
| struct ContextState; | |
| } // namespace gles2 | |
| namespace raster { | |
| class GrCacheController; | |
| class GrShaderCache; | |
| class GraphiteCacheController; | |
| class RasterDecoderTestBase; | |
| } // namespace raster | |
| class GPU_GLES2_EXPORT SharedContextState | |
| : public base::trace_event::MemoryDumpProvider, | |
| public gpu::GLContextVirtualDelegate, | |
| public base::RefCounted<SharedContextState>, | |
| public GrContextOptions::ShaderErrorHandler { | |
| public: | |
| using ContextLostCallback = | |
| base::OnceCallback<void(bool, error::ContextLostReason)>; | |
| // This interface is used by the embedder to set custom GrContextOptions which | |
| // are passed to Skia. | |
| class GrContextOptionsProvider { | |
| public: | |
| ~GrContextOptionsProvider() = default; | |
| // The passed GrContextOptions will have the default fields set. The | |
| // embedder may modify the options as needed. | |
| virtual void SetCustomGrContextOptions(GrContextOptions& options) const = 0; | |
| }; | |
| // TODO(vikassoni): Refactor code to have seperate constructor for GL and | |
| // Vulkan and not initialize/use GL related info for vulkan and vice-versa. | |
| SharedContextState( | |
| scoped_refptr<gl::GLShareGroup> share_group, | |
| scoped_refptr<gl::GLSurface> surface, | |
| scoped_refptr<gl::GLContext> context, | |
| bool use_virtualized_gl_contexts, | |
| ContextLostCallback context_lost_callback, | |
| GrContextType gr_context_type, | |
| VulkanContextProvider* vulkan_context_provider = nullptr, | |
| DawnContextProvider* dawn_context_provider = nullptr, | |
| scoped_refptr<gpu::MemoryTracker::Observer> peak_memory_monitor = nullptr, | |
| bool direct_rendering_display_compositor_enabled = false, | |
| bool created_on_compositor_gpu_thread = false, | |
| const gpu::SharedContextState::GrContextOptionsProvider* | |
| gr_context_options_provider = nullptr); | |
| SharedContextState(const SharedContextState&) = delete; | |
| SharedContextState& operator=(const SharedContextState&) = delete; | |
| bool InitializeSkia( | |
| const GpuPreferences& gpu_preferences, | |
| const GpuDriverBugWorkarounds& workarounds, | |
| gpu::raster::GrShaderCache* gr_cache = nullptr, | |
| scoped_refptr<GpuPersistentCache> persistent_cache = nullptr, | |
| GpuProcessShmCount* use_shader_cache_shm_count = nullptr, | |
| gl::ProgressReporter* progress_reporter = nullptr); | |
| bool GrContextIsGL() const { | |
| return gr_context_type_ == GrContextType::kGL; | |
| } | |
| bool GrContextIsVulkan() const { | |
| return gr_context_type_ == GrContextType::kVulkan; | |
| } | |
| bool IsGraphiteDawn() const; | |
| bool IsGraphiteDawnMetal() const; | |
| bool IsGraphiteDawnD3D() const; | |
| bool IsGraphiteDawnD3D11() const; | |
| bool IsGraphiteDawnD3D12() const; | |
| bool IsGraphiteDawnVulkan() const; | |
| bool IsGraphiteDawnVulkanSwiftShader() const; | |
| bool IsGraphiteVulkan() const; | |
| bool InitializeGL(const GpuPreferences& gpu_preferences, | |
| const GpuDriverBugWorkarounds& gpu_driver_bug_workarounds, | |
| const GpuFeatureInfo& gpu_feature_info); | |
| bool IsGLInitialized() const { return !!feature_info_; } | |
| bool FlushAndSubmit(bool sync_to_cpu); | |
| bool FlushGraphiteRecorder(); | |
| bool FlushWriteAccess(SkiaImageRepresentation::ScopedWriteAccess* access); | |
| bool SubmitIfNecessary(std::vector<GrBackendSemaphore> signal_semaphores, | |
| bool need_graphite_submit); | |
| // Sets the active SharedContextState for the calling thread using | |
| // thread-local storage. This is typically set by the thread owner (such as | |
| // GpuChannelManager on the GPU main thread, CompositorGpuThread on the | |
| // compositor thread, or OutputSurfaceProviderWebView on WebView render | |
| // thread) to allow downstream multi-threaded components (such as | |
| // CompoundImageBacking fallback copies) to look up the active context on the | |
| // current thread. | |
| // Note that this and other methods below | |
| // GetForCurrentThread()/ClearForCurrentThread() are currently not applicable | |
| // to webview(hence OutputSurfaceProviderWebView) and should not be used for | |
| // webview. | |
| static void SetForCurrentThread(SharedContextState* state); | |
| // Returns the active SharedContextState for the current thread, or nullptr | |
| // if none is registered. | |
| static SharedContextState* GetForCurrentThread(); | |
| // Clears the active SharedContextState for the current thread. Must be | |
| // called before the registered SharedContextState is destroyed. | |
| static void ClearForCurrentThread(); | |
| // Returns true if context state is using GL, either for Skia to run on | |
| // or if there is no skia context and context state exists for WebGL fallback | |
| // only. | |
| bool IsUsingGL() const; | |
| bool MakeCurrent(gl::GLSurface* surface, bool needs_gl = false); | |
| void ReleaseCurrent(gl::GLSurface* surface); | |
| void MarkContextLost(error::ContextLostReason reason = error::kUnknown); | |
| bool IsCurrent(gl::GLSurface* surface, bool needs_gl = false); | |
| // Immediately evicts unlocked resources (scratch resources under moderate | |
| // pressure, or all resources under critical pressure) down to `memory_limit`. | |
| void PurgeMemory(base::MemoryLimit memory_limit); | |
| // Updates internal memory target budgets non-destructively without forcing | |
| // immediate resource purges. | |
| void OnUpdateMemoryLimit(base::MemoryLimit memory_limit); | |
| void UpdateSkiaOwnedMemorySize(); | |
| uint64_t GetMemoryUsage(); | |
| void PessimisticallyResetGrContext() const; | |
| void StoreVkPipelineCacheIfNeeded(); | |
| void UseShaderCache( | |
| std::optional<gpu::raster::GrShaderCache::ScopedCacheUse>& cache_use, | |
| int32_t client_id) const; | |
| GLFormatCaps GetGLFormatCaps() { return GLFormatCaps(feature_info()); } | |
| gl::GLShareGroup* share_group() const { return share_group_.get(); } | |
| gl::GLContext* context() const { return context_.get(); } | |
| gl::GLContext* real_context() const { return real_context_.get(); } | |
| gl::GLSurface* surface() const; | |
| gl::GLDisplay* display(); // non const since it calls GLSurface::GetGLDisplay | |
| VulkanContextProvider* vk_context_provider() const { | |
| return vk_context_provider_; | |
| } | |
| DawnContextProvider* dawn_context_provider() const { | |
| return dawn_context_provider_; | |
| } | |
| gl::ProgressReporter* progress_reporter() const { return progress_reporter_; } | |
| // Ganesh/Graphite contexts may only be used on the GPU main thread. | |
| GrDirectContext* gr_context() const { return gr_context_; } | |
| gpu::GraphiteSharedContext* graphite_shared_context() const; | |
| // Graphite recorder for GPU main thread, used by RasterDecoder, | |
| // SkiaOutputSurfaceImplOnGpu, etc. | |
| skgpu::graphite::Recorder* gpu_main_graphite_recorder() const { | |
| return gpu_main_graphite_recorder_.get(); | |
| } | |
| // Graphite recorder for Viz compositor thread, used by SkiaOutputSurfaceImpl. | |
| skgpu::graphite::Recorder* viz_compositor_graphite_recorder() const { | |
| return viz_compositor_graphite_recorder_.get(); | |
| } | |
| // Returns the Graphite cache controller for the Viz compositor thread. | |
| // This is a weak pointer that is invalidated and dereferenced on the Viz | |
| // compositor thread. Returned as a pointer to the WeakPtr so that the caller | |
| // can create a new cache controller if needed. | |
| base::WeakPtr<raster::GraphiteCacheController>* | |
| viz_compositor_graphite_cache_controller_weak_ptr() { | |
| return &viz_compositor_graphite_cache_controller_; | |
| } | |
| GrContextType gr_context_type() const { return gr_context_type_; } | |
| // Handles Skia-reported shader compilation errors. | |
| void compileError(const char* shader, | |
| const char* errors, | |
| bool shaderWasCached) override; | |
| gles2::FeatureInfo* feature_info() { return feature_info_.get(); } | |
| gles2::ContextState* context_state() const { return context_state_.get(); } | |
| bool context_lost() const { return !!context_lost_reason_; } | |
| std::optional<error::ContextLostReason> context_lost_reason() { | |
| return context_lost_reason_; | |
| } | |
| base::WeakPtr<SharedContextState> GetWeakPtr() { | |
| return weak_ptr_factory_.GetWeakPtr(); | |
| } | |
| bool need_context_state_reset() const { return need_context_state_reset_; } | |
| void set_need_context_state_reset(bool reset) { | |
| need_context_state_reset_ = reset; | |
| } | |
| ServiceTransferCache* transfer_cache() { return transfer_cache_.get(); } | |
| std::vector<uint8_t>* scratch_deserialization_buffer() { | |
| return &scratch_deserialization_buffer_; | |
| } | |
| bool use_virtualized_gl_contexts() const { | |
| return use_virtualized_gl_contexts_; | |
| } | |
| bool support_vulkan_external_object() const { | |
| return support_vulkan_external_object_; | |
| } | |
| bool support_gl_external_object_flags() const { | |
| return support_gl_external_object_flags_; | |
| } | |
| bool is_drdc_enabled() const { return is_drdc_enabled_; } | |
| gpu::MemoryTracker* memory_tracker() { return memory_tracker_.get(); } | |
| gpu::MemoryTypeTracker* memory_type_tracker() { | |
| return &memory_type_tracker_; | |
| } | |
| #if BUILDFLAG(ENABLE_VULKAN) && (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_FUCHSIA)) | |
| ExternalSemaphorePool* external_semaphore_pool() { | |
| return external_semaphore_pool_.get(); | |
| } | |
| #endif | |
| // base::trace_event::MemoryDumpProvider implementation. | |
| bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, | |
| base::trace_event::ProcessMemoryDump* pmd) override; | |
| // Observer class which is notified when the context is lost. | |
| class ContextLostObserver { | |
| public: | |
| virtual void OnContextLost() = 0; | |
| protected: | |
| virtual ~ContextLostObserver() = default; | |
| }; | |
| void AddContextLostObserver(ContextLostObserver* obs); | |
| void RemoveContextLostObserver(ContextLostObserver* obs); | |
| // Creating a SkSurface backed by FBO takes ~500 usec and holds ~50KB of heap | |
| // on Android circa 2020. Caching them is a memory/CPU tradeoff. | |
| void CacheSkSurface(void* key, sk_sp<SkSurface> surface) { | |
| sk_surface_cache_.Put(key, surface); | |
| } | |
| sk_sp<SkSurface> GetCachedSkSurface(void* key) { | |
| auto found = sk_surface_cache_.Get(key); | |
| if (found == sk_surface_cache_.end()) | |
| return nullptr; | |
| return found->second; | |
| } | |
| void EraseCachedSkSurface(void* key) { | |
| auto found = sk_surface_cache_.Peek(key); | |
| if (found != sk_surface_cache_.end()) | |
| sk_surface_cache_.Erase(found); | |
| } | |
| // Supports DCHECKs. OK to be approximate. | |
| bool CachedSkSurfaceIsUnique(void* key) { | |
| auto found = sk_surface_cache_.Peek(key); | |
| // It was purged. Assume it was unique. | |
| if (found == sk_surface_cache_.end()) | |
| return true; | |
| return found->second->unique(); | |
| } | |
| // Updates |context_lost_reason| and returns true if lost | |
| // (e.g. VK_ERROR_DEVICE_LOST or GL_UNKNOWN_CONTEXT_RESET_ARB). | |
| bool CheckResetStatus(bool needs_gl); | |
| bool device_needs_reset() { return device_needs_reset_; } | |
| void ScheduleSkiaCleanup(); | |
| int32_t GetMaxTextureSize(); | |
| int32_t GetMaxArrayTextureLayers(); | |
| #if BUILDFLAG(IS_WIN) | |
| // Get the D3D device and command queue used for compositing. | |
| Microsoft::WRL::ComPtr<ID3D11Device> GetD3D11Device() const; | |
| Microsoft::WRL::ComPtr<ID3D12CommandQueue> GetD3D12CommandQueue() const; | |
| #endif | |
| private: | |
| friend class base::RefCounted<SharedContextState>; | |
| friend class raster::RasterDecoderTestBase; | |
| FRIEND_TEST_ALL_PREFIXES(SharedContextStateTest, InitFailsIfLostContext); | |
| FRIEND_TEST_ALL_PREFIXES(SharedContextStateTest, | |
| GLOptionsProviderSetsCustomOptions); | |
| FRIEND_TEST_ALL_PREFIXES(SharedContextStateTest, | |
| VulkanOptionsProviderSetsCustomOptions); | |
| ~SharedContextState() override; | |
| bool InitializeGLWithFeatureInfo( | |
| scoped_refptr<gles2::FeatureInfo> feature_info); | |
| bool InitializeGanesh( | |
| const GpuPreferences& gpu_preferences, | |
| const GpuDriverBugWorkarounds& workarounds, | |
| gpu::raster::GrShaderCache* gr_cache = nullptr, | |
| scoped_refptr<GpuPersistentCache> persistent_cache = nullptr, | |
| GpuProcessShmCount* use_shader_cache_shm_count = nullptr, | |
| gl::ProgressReporter* progress_reporter = nullptr); | |
| bool InitializeGraphite(const GpuPreferences& gpu_preferences, | |
| const GpuDriverBugWorkarounds& workarounds, | |
| GpuProcessShmCount* use_shader_cache_shm_count); | |
| std::optional<error::ContextLostReason> GetResetStatus(bool needs_gl); | |
| void PurgeGaneshMemory(base::MemoryLimit memory_limit); | |
| void PurgeGraphiteMemory(base::MemoryLimit memory_limit); | |
| // gpu::GLContextVirtualDelegate implementation. | |
| bool initialized() const override; | |
| const gles2::ContextState* GetContextState() override; | |
| void RestoreState(const gles2::ContextState* prev_state) override; | |
| void RestoreGlobalState() const override; | |
| void ClearAllAttributes() const override; | |
| void RestoreActiveTexture() const override; | |
| void RestoreAllTextureUnitAndSamplerBindings( | |
| const gles2::ContextState* prev_state) const override; | |
| void RestoreActiveTextureUnitBinding(unsigned int target) const override; | |
| void RestoreBufferBinding(unsigned int target) override; | |
| void RestoreBufferBindings() const override; | |
| void RestoreFramebufferBindings() const override; | |
| void RestoreRenderbufferBindings() override; | |
| void RestoreProgramBindings() const override; | |
| void RestoreTextureUnitBindings(unsigned unit) const override; | |
| void RestoreVertexAttribArray(unsigned index) override; | |
| void RestoreAllExternalTextureBindingsIfNeeded() override; | |
| QueryManager* GetQueryManager() override; | |
| bool use_virtualized_gl_contexts_ = false; | |
| bool support_vulkan_external_object_ = false; | |
| bool support_gl_external_object_flags_ = false; | |
| ContextLostCallback context_lost_callback_; | |
| const GrContextType gr_context_type_; | |
| scoped_refptr<MemoryTracker> memory_tracker_shared_context_state_; | |
| scoped_refptr<MemoryTracker> memory_tracker_; | |
| gpu::MemoryTypeTracker memory_type_tracker_; | |
| const raw_ptr<VulkanContextProvider> vk_context_provider_ = nullptr; | |
| const raw_ptr<DawnContextProvider> dawn_context_provider_ = nullptr; | |
| raw_ptr<const GrContextOptionsProvider> gr_context_options_provider_ = | |
| nullptr; | |
| bool created_on_compositor_gpu_thread_ = false; | |
| bool is_drdc_enabled_ = false; | |
| raw_ptr<GrDirectContext> gr_context_ = nullptr; | |
| std::unique_ptr<skgpu::graphite::Recorder> gpu_main_graphite_recorder_; | |
| std::unique_ptr<skgpu::graphite::Recorder> viz_compositor_graphite_recorder_; | |
| // These two are only used if Precompilation is enabled | |
| std::unique_ptr<skgpu::graphite::PrecompileContext> precompile_context_; | |
| base::RepeatingTimer pipeline_cache_stats_timer_; | |
| scoped_refptr<gl::GLShareGroup> share_group_; | |
| scoped_refptr<gl::GLContext> context_; | |
| scoped_refptr<gl::GLContext> real_context_; | |
| // Most recent surface that this ShareContextState was made current with. | |
| // Avoids a call to MakeCurrent with a different surface, if we don't | |
| // care which surface is current. | |
| raw_ptr<gl::GLSurface, DanglingUntriaged> last_current_surface_ = nullptr; | |
| scoped_refptr<gles2::FeatureInfo> feature_info_; | |
| // raster decoders and display compositor share this context_state_. | |
| std::unique_ptr<gles2::ContextState> context_state_; | |
| raw_ptr<gl::ProgressReporter, DanglingUntriaged> progress_reporter_ = nullptr; | |
| sk_sp<GrDirectContext> owned_gr_context_; | |
| std::unique_ptr<ServiceTransferCache> transfer_cache_; | |
| std::vector<uint8_t> scratch_deserialization_buffer_; | |
| raw_ptr<gpu::raster::GrShaderCache, DanglingUntriaged> gr_shader_cache_ = | |
| nullptr; | |
| scoped_refptr<GpuPersistentCache> persistent_cache_ = nullptr; | |
| raw_ptr<GpuProcessShmCount, DanglingUntriaged> use_shader_cache_shm_count_ = | |
| nullptr; | |
| // |need_context_state_reset| is set whenever Skia may have altered the | |
| // driver's GL state. | |
| bool need_context_state_reset_ = false; | |
| std::optional<error::ContextLostReason> context_lost_reason_; | |
| base::ObserverList<ContextLostObserver>::Unchecked context_lost_observers_; | |
| base::LRUCache<void*, sk_sp<SkSurface>> sk_surface_cache_; | |
| bool device_needs_reset_ = false; | |
| base::Time last_gl_check_graphics_reset_status_; | |
| bool disable_check_reset_status_throttling_for_test_ = false; | |
| #if BUILDFLAG(ENABLE_VULKAN) && (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_FUCHSIA)) | |
| std::unique_ptr<ExternalSemaphorePool> external_semaphore_pool_; | |
| #endif | |
| std::unique_ptr<raster::GrCacheController> gr_cache_controller_; | |
| // The graphite cache controller for |graphite_context_| and | |
| // |gpu_main_graphite_recorder_|. | |
| scoped_refptr<raster::GraphiteCacheController> | |
| gpu_main_graphite_cache_controller_; | |
| // The graphite cache controller for |viz_compositor_graphite_recorder_|. | |
| // Held as a weak pointer that is invalidated and dereferenced on the Viz | |
| // compositor thread. | |
| base::WeakPtr<raster::GraphiteCacheController> | |
| viz_compositor_graphite_cache_controller_; | |
| std::optional<int> max_texture_size_; | |
| std::optional<int> max_array_texture_layers_; | |
| size_t max_resource_cache_bytes_ = 0; | |
| // A SharedContextState is created on, and used from, a single gpu thread | |
| // (the gpu main thread, or the CompositorGpuThread when DrDc is enabled). | |
| THREAD_CHECKER(context_thread_checker_); | |
| base::WeakPtrFactory<SharedContextState> weak_ptr_factory_{this}; | |
| }; | |
| } // namespace gpu | |
| #endif // GPU_COMMAND_BUFFER_SERVICE_SHARED_CONTEXT_STATE_H_ |