blob: 68c0076da8fcf38ac86a036a2a5595bcfcd9e250 [file] [log] [blame]
// 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/observer_list.h"
#include "base/task/single_thread_task_runner.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/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 <wrl/client.h>
#endif
namespace gl {
class GLContext;
class GLDisplay;
class GLShareGroup;
class GLSurface;
} // namespace gl
namespace viz {
class MetalContextProvider;
class VulkanContextProvider;
} // namespace viz
namespace skgpu::graphite {
class PrecompileContext;
class Recorder;
} // namespace skgpu::graphite
namespace gpu {
class DawnContextProvider;
class ExternalSemaphorePool;
class GpuDriverBugWorkarounds;
class GpuProcessShmCount;
class ServiceTransferCache;
class GraphiteSharedContext;
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,
viz::VulkanContextProvider* vulkan_context_provider = nullptr,
viz::MetalContextProvider* metal_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* 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 IsGraphiteMetal() const;
bool IsGraphiteDawnMetal() const;
bool IsGraphiteDawnD3D() const;
bool IsGraphiteDawnD3D11() const;
bool IsGraphiteDawnVulkan() const;
bool IsGraphiteDawnVulkanSwiftShader() const;
bool InitializeGL(const GpuPreferences& gpu_preferences,
scoped_refptr<gles2::FeatureInfo> feature_info);
bool IsGLInitialized() const { return !!feature_info_; }
void FlushAndSubmit(bool sync_to_cpu);
void FlushWriteAccess(SkiaImageRepresentation::ScopedWriteAccess* access);
void SubmitIfNecessary(std::vector<GrBackendSemaphore> signal_semaphores,
bool need_graphite_submit);
// 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);
void PurgeMemory(
base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);
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
viz::VulkanContextProvider* vk_context_provider() const {
return vk_context_provider_;
}
viz::MetalContextProvider* metal_context_provider() const {
return metal_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();
}
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_;
}
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) || BUILDFLAG(IS_WIN))
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();
#if BUILDFLAG(IS_WIN)
// Get the D3D11 device used for the compositing.
Microsoft::WRL::ComPtr<ID3D11Device> GetD3D11Device() const;
#endif
private:
friend class base::RefCounted<SharedContextState>;
friend class raster::RasterDecoderTestBase;
FRIEND_TEST_ALL_PREFIXES(SharedContextStateTest,
GLOptionsProviderSetsCustomOptions);
FRIEND_TEST_ALL_PREFIXES(SharedContextStateTest,
VulkanOptionsProviderSetsCustomOptions);
~SharedContextState() override;
bool InitializeGanesh(
const GpuPreferences& gpu_preferences,
const GpuDriverBugWorkarounds& workarounds,
gpu::raster::GrShaderCache* cache,
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);
void FlushGraphiteRecorder();
std::optional<error::ContextLostReason> GetResetStatus(bool needs_gl);
// 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<viz::VulkanContextProvider> vk_context_provider_ = nullptr;
const raw_ptr<viz::MetalContextProvider> metal_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, DanglingUntriaged> 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;
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) || BUILDFLAG(IS_WIN))
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_;
std::optional<int> max_texture_size_;
base::WeakPtrFactory<SharedContextState> weak_ptr_factory_{this};
};
} // namespace gpu
#endif // GPU_COMMAND_BUFFER_SERVICE_SHARED_CONTEXT_STATE_H_