duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

opengl_device.h (10265B)


      1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
      2 // SPDX-License-Identifier: (GPL-3.0 OR PolyForm-Strict-1.0.0)
      3 
      4 #pragma once
      5 
      6 #include "gpu_device.h"
      7 #include "gpu_framebuffer_manager.h"
      8 #include "gpu_shader_cache.h"
      9 #include "opengl_context.h"
     10 #include "opengl_loader.h"
     11 #include "opengl_pipeline.h"
     12 #include "opengl_texture.h"
     13 
     14 #include <cstdio>
     15 #include <memory>
     16 #include <string_view>
     17 #include <tuple>
     18 
     19 class OpenGLPipeline;
     20 class OpenGLStreamBuffer;
     21 class OpenGLTexture;
     22 class OpenGLDownloadTexture;
     23 
     24 class OpenGLDevice final : public GPUDevice
     25 {
     26   friend OpenGLTexture;
     27   friend OpenGLDownloadTexture;
     28 
     29 public:
     30   OpenGLDevice();
     31   ~OpenGLDevice();
     32 
     33   ALWAYS_INLINE static OpenGLDevice& GetInstance() { return *static_cast<OpenGLDevice*>(g_gpu_device.get()); }
     34   ALWAYS_INLINE static OpenGLStreamBuffer* GetTextureStreamBuffer()
     35   {
     36     return GetInstance().m_texture_stream_buffer.get();
     37   }
     38   ALWAYS_INLINE static bool IsGLES() { return GetInstance().m_gl_context->IsGLES(); }
     39   static void BindUpdateTextureUnit();
     40   static bool ShouldUsePBOsForDownloads();
     41   static void SetErrorObject(Error* errptr, std::string_view prefix, GLenum glerr);
     42 
     43   RenderAPI GetRenderAPI() const override;
     44 
     45   bool HasSurface() const override;
     46   void DestroySurface() override;
     47 
     48   bool UpdateWindow() override;
     49   void ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) override;
     50 
     51   std::string GetDriverInfo() const override;
     52 
     53   void ExecuteAndWaitForGPUIdle() override;
     54 
     55   std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
     56                                             GPUTexture::Type type, GPUTexture::Format format,
     57                                             const void* data = nullptr, u32 data_stride = 0) override;
     58   std::unique_ptr<GPUSampler> CreateSampler(const GPUSampler::Config& config) override;
     59   std::unique_ptr<GPUTextureBuffer> CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements) override;
     60 
     61   std::unique_ptr<GPUDownloadTexture> CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format) override;
     62   std::unique_ptr<GPUDownloadTexture> CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format,
     63                                                             void* memory, size_t memory_size,
     64                                                             u32 memory_stride) override;
     65 
     66   bool SupportsTextureFormat(GPUTexture::Format format) const override;
     67   void CopyTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u32 dst_layer, u32 dst_level, GPUTexture* src,
     68                          u32 src_x, u32 src_y, u32 src_layer, u32 src_level, u32 width, u32 height) override;
     69   void ResolveTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u32 dst_layer, u32 dst_level, GPUTexture* src,
     70                             u32 src_x, u32 src_y, u32 width, u32 height) override;
     71   void ClearRenderTarget(GPUTexture* t, u32 c) override;
     72   void ClearDepth(GPUTexture* t, float d) override;
     73   void InvalidateRenderTarget(GPUTexture* t) override;
     74 
     75   std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data,
     76                                                     Error* error) override;
     77   std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language,
     78                                                     std::string_view source, const char* entry_point,
     79                                                     DynamicHeapArray<u8>* out_binary, Error* error) override;
     80   std::unique_ptr<GPUPipeline> CreatePipeline(const GPUPipeline::GraphicsConfig& config, Error* error) override;
     81 
     82   void PushDebugGroup(const char* name) override;
     83   void PopDebugGroup() override;
     84   void InsertDebugMessage(const char* msg) override;
     85 
     86   void MapVertexBuffer(u32 vertex_size, u32 vertex_count, void** map_ptr, u32* map_space,
     87                        u32* map_base_vertex) override;
     88   void UnmapVertexBuffer(u32 vertex_size, u32 vertex_count) override;
     89   void MapIndexBuffer(u32 index_count, DrawIndex** map_ptr, u32* map_space, u32* map_base_index) override;
     90   void UnmapIndexBuffer(u32 used_index_count) override;
     91   void PushUniformBuffer(const void* data, u32 data_size) override;
     92   void* MapUniformBuffer(u32 size) override;
     93   void UnmapUniformBuffer(u32 size) override;
     94   void SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds,
     95                         GPUPipeline::RenderPassFlag feedback_loop = GPUPipeline::NoRenderPassFlags) override;
     96   void SetPipeline(GPUPipeline* pipeline) override;
     97   void SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* sampler) override;
     98   void SetTextureBuffer(u32 slot, GPUTextureBuffer* buffer) override;
     99   void SetViewport(const GSVector4i rc) override;
    100   void SetScissor(const GSVector4i rc) override;
    101   void Draw(u32 vertex_count, u32 base_vertex) override;
    102   void DrawIndexed(u32 index_count, u32 base_index, u32 base_vertex) override;
    103   void DrawIndexedWithBarrier(u32 index_count, u32 base_index, u32 base_vertex, DrawBarrier type) override;
    104 
    105   void SetVSyncMode(GPUVSyncMode mode, bool allow_present_throttle) override;
    106 
    107   bool BeginPresent(bool skip_present, u32 clear_color) override;
    108   void EndPresent(bool explicit_present) override;
    109   void SubmitPresent() override;
    110 
    111   bool SetGPUTimingEnabled(bool enabled) override;
    112   float GetAndResetAccumulatedGPUTime() override;
    113 
    114   void CommitClear(OpenGLTexture* tex);
    115   void CommitRTClearInFB(OpenGLTexture* tex, u32 idx);
    116   void CommitDSClearInFB(OpenGLTexture* tex);
    117 
    118   GLuint LookupProgramCache(const OpenGLPipeline::ProgramCacheKey& key, const GPUPipeline::GraphicsConfig& plconfig, Error* error);
    119   GLuint CompileProgram(const GPUPipeline::GraphicsConfig& plconfig, Error* error);
    120   void PostLinkProgram(const GPUPipeline::GraphicsConfig& plconfig, GLuint program_id);
    121   void UnrefProgram(const OpenGLPipeline::ProgramCacheKey& key);
    122 
    123   OpenGLPipeline::VertexArrayCache::const_iterator LookupVAOCache(const OpenGLPipeline::VertexArrayCacheKey& key, Error* error);
    124   GLuint CreateVAO(std::span<const GPUPipeline::VertexAttribute> attributes, u32 stride, Error* error);
    125   void UnrefVAO(const OpenGLPipeline::VertexArrayCacheKey& key);
    126 
    127   void SetActiveTexture(u32 slot);
    128   void UnbindTexture(GLuint id);
    129   void UnbindTexture(OpenGLTexture* tex);
    130   void UnbindSSBO(GLuint id);
    131   void UnbindSampler(GLuint id);
    132   void UnbindPipeline(const OpenGLPipeline* pl);
    133 
    134 protected:
    135   bool CreateDevice(std::string_view adapter, bool threaded_presentation,
    136                     std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features,
    137                     Error* error) override;
    138   void DestroyDevice() override;
    139 
    140   bool OpenPipelineCache(const std::string& filename) override;
    141   bool GetPipelineCacheData(DynamicHeapArray<u8>* data) override;
    142 
    143 private:
    144   static constexpr u8 NUM_TIMESTAMP_QUERIES = 3;
    145 
    146   static constexpr GLenum UPDATE_TEXTURE_UNIT = GL_TEXTURE8;
    147 
    148   static constexpr u32 VERTEX_BUFFER_SIZE = 8 * 1024 * 1024;
    149   static constexpr u32 INDEX_BUFFER_SIZE = 4 * 1024 * 1024;
    150   static constexpr u32 UNIFORM_BUFFER_SIZE = 2 * 1024 * 1024;
    151   static constexpr u32 TEXTURE_STREAM_BUFFER_SIZE = 16 * 1024 * 1024;
    152 
    153   bool CheckFeatures(FeatureMask disabled_features);
    154   bool CreateBuffers();
    155   void DestroyBuffers();
    156 
    157   void SetSwapInterval();
    158   void RenderBlankFrame();
    159 
    160   s32 IsRenderTargetBound(const GPUTexture* tex) const;
    161   static GLuint CreateFramebuffer(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds, u32 flags);
    162   static void DestroyFramebuffer(GLuint fbo);
    163 
    164   void UpdateViewport();
    165   void UpdateScissor();
    166 
    167   void CreateTimestampQueries();
    168   void DestroyTimestampQueries();
    169   void PopTimestampQuery();
    170   void KickTimestampQuery();
    171 
    172   GLuint CreateProgramFromPipelineCache(const OpenGLPipeline::ProgramCacheItem& it,
    173                                         const GPUPipeline::GraphicsConfig& plconfig);
    174   void AddToPipelineCache(OpenGLPipeline::ProgramCacheItem* it);
    175   bool DiscardPipelineCache();
    176   void ClosePipelineCache();
    177 
    178   void ApplyRasterizationState(GPUPipeline::RasterizationState rs);
    179   void ApplyDepthState(GPUPipeline::DepthState ds);
    180   void ApplyBlendState(GPUPipeline::BlendState bs);
    181 
    182   void SetVertexBufferOffsets(u32 base_vertex);
    183 
    184   std::unique_ptr<OpenGLContext> m_gl_context;
    185 
    186   std::unique_ptr<OpenGLStreamBuffer> m_vertex_buffer;
    187   std::unique_ptr<OpenGLStreamBuffer> m_index_buffer;
    188   std::unique_ptr<OpenGLStreamBuffer> m_uniform_buffer;
    189   std::unique_ptr<OpenGLStreamBuffer> m_texture_stream_buffer;
    190 
    191   // TODO: pass in file instead of blob for pipeline cache
    192   OpenGLPipeline::VertexArrayCache m_vao_cache;
    193   OpenGLPipeline::ProgramCache m_program_cache;
    194   GPUFramebufferManager<GLuint, CreateFramebuffer, DestroyFramebuffer> m_framebuffer_manager;
    195 
    196   // VAO cache - fixed max as key
    197   OpenGLPipeline::VertexArrayCache::const_iterator m_last_vao = m_vao_cache.cend();
    198   GPUPipeline::BlendState m_last_blend_state = {};
    199   GPUPipeline::RasterizationState m_last_rasterization_state = {};
    200   GPUPipeline::DepthState m_last_depth_state = {};
    201   GLuint m_uniform_buffer_alignment = 1;
    202   GLuint m_last_program = 0;
    203   u32 m_last_texture_unit = 0;
    204   std::array<std::pair<GLuint, GLuint>, MAX_TEXTURE_SAMPLERS> m_last_samplers = {};
    205   GLuint m_last_ssbo = 0;
    206   GSVector4i m_last_viewport = {};
    207   GSVector4i m_last_scissor = GSVector4i::cxpr(0, 0, 1, 1);
    208 
    209   // Misc framebuffers
    210   GLuint m_read_fbo = 0;
    211   GLuint m_write_fbo = 0;
    212 
    213   GLuint m_current_fbo = 0;
    214   u32 m_num_current_render_targets = 0;
    215   std::array<OpenGLTexture*, MAX_RENDER_TARGETS> m_current_render_targets = {};
    216   OpenGLTexture* m_current_depth_target = nullptr;
    217 
    218   OpenGLPipeline* m_current_pipeline = nullptr;
    219 
    220   std::array<GLuint, NUM_TIMESTAMP_QUERIES> m_timestamp_queries = {};
    221   float m_accumulated_gpu_time = 0.0f;
    222   u8 m_read_timestamp_query = 0;
    223   u8 m_write_timestamp_query = 0;
    224   u8 m_waiting_timestamp_queries = 0;
    225   bool m_timestamp_query_started = false;
    226 
    227   std::FILE* m_pipeline_disk_cache_file = nullptr;
    228   std::string m_pipeline_disk_cache_filename;
    229   u32 m_pipeline_disk_cache_data_end = 0;
    230   bool m_pipeline_disk_cache_changed = false;
    231 
    232   bool m_disable_pbo = false;
    233   bool m_disable_async_download = false;
    234 };