20#ifndef RHI_RENDER_THREAD_H
21#define RHI_RENDER_THREAD_H
36#include <condition_variable>
44#include <unordered_map>
45#include <unordered_set>
89 void SetGlyphAtlas( std::shared_ptr<const RHI_GLYPH_ATLAS_DATA> aAtlas );
106 bool WaitForFence( std::chrono::milliseconds aTimeout = std::chrono::milliseconds( 2000 ) );
167 uint32_t& aBackingW, uint32_t& aBackingH );
176 void ThreadMain( std::promise<bool> aStarted );
219 uint32_t aStaticDrawMargin = 0 );
232 bool runFenced( std::function<
void()> aWork, std::chrono::milliseconds aTimeout );
240 const void* aData,
size_t aSize );
300 std::unordered_map<RHI_WINDOW_ID, WINDOW_STATE>
m_windows;
void CreateWindowFBOs(WINDOW_STATE &aWS)
RHI_BufferHandle m_unitQuadBuffer
RHI_BufferHandle m_quadIndexBuffer
its 2 triangles over those corners
std::mutex m_glyphAtlasMutex
std::unique_ptr< RHI_DEVICE > m_device
SYNC_QUEUE< RHI_UPLOAD_COMMAND > m_uploadQueue
bool prepareCursor(WINDOW_STATE &aWS)
Fill the cursor's uniforms.
std::unordered_set< RHI_WINDOW_ID > m_presentedWindows
bool WaitForFence(std::chrono::milliseconds aTimeout=std::chrono::milliseconds(2000))
Block until every command submitted before this call has been processed.
void ProcessActiveWindows(bool aIgnorePacing=false)
std::unordered_map< RHI_WINDOW_ID, WINDOW_STATE > m_windows
RHI_BufferHandle m_quadCornerBuffer
the unit quad's 4 corners
void ThreadMain(std::promise< bool > aStarted)
RHI_BACKEND GetBackendType() const
RHI_DEVICE_FACTORY m_deviceFactory
void deferFrameUntil(WINDOW_STATE::Clock::time_point aDue)
void DestroyRenderInfrastructure()
bool EnsureSwapchain(WINDOW_STATE &aWS, const char *aReason)
RHI_RenderPassHandle m_geometryRenderPass
void HandleSwapchainDestroy(const RHI_CMD_SWAPCHAIN_DESTROY &aCmd)
std::optional< WINDOW_STATE::Clock::time_point > m_deferredFrameDue
Earliest time a window held to its display's refresh rate is due, so the loop wakes for it.
RHI_RenderPassHandle m_geometryDepthLoadRenderPass
clears colour, keeps depth
void AddDeviceLostListener(const void *aOwner, std::function< void()> aListener)
Call aListener on the render thread when the device is lost.
bool runFenced(std::function< void()> aWork, std::chrono::milliseconds aTimeout)
Run work on the render thread after everything queued before it.
std::atomic< bool > m_uploadsPending
Set by producers and cleared by the drain so the loop can sleep without missing uploads.
bool m_acceptingWork
Guarded by m_workMutex.
void HandleSwapchainResize(const RHI_CMD_SWAPCHAIN_RESIZE &aCmd)
std::mutex m_presentedMutex
Window IDs are never reused, so an entry outliving its window is harmless.
std::atomic< bool > m_running
std::mutex m_deviceMutex
Guards the m_device pointer, not the device, against UI thread reads racing its creation or destructi...
void RemoveDeviceLostListener(const void *aOwner)
Once this returns, the owner's listener is not running and will not be called.
RHI_RenderPassHandle m_geometryLoadRenderPass
static void ComputeBackingResolution(uint32_t aLogicalW, uint32_t aLogicalH, float aDpiScale, uint32_t &aBackingW, uint32_t &aBackingH)
Compute the physical pixel backing size from logical size and DPI scale, at least 1x1.
uint32_t GetMaxTextureSize() const
RENDER_THREAD(const RENDER_THREAD &)=delete
void DestroyWindowUniforms(WINDOW_STATE &aWS)
bool IsDeviceLost() const
bool InitRenderInfrastructure()
void SetGlyphAtlas(std::shared_ptr< const RHI_GLYPH_ATLAS_DATA > aAtlas)
Give the track shaders the font atlas glyph instances draw from.
void SubmitUpload(RHI_UPLOAD_COMMAND aCmd)
Callable from any thread.
RHI_TextureHandle m_glyphTexture
The font atlas the track shaders draw glyphs from, its glyph table and their bind group.
bool HasPresented(RHI_WINDOW_ID aWindowId) const
RHI_BufferHandle m_glyphTable
bool ReadbackWindowPixels(RHI_WINDOW_ID aWindowId, wxImage &aImage)
Read back a window's picture at backing resolution without the overlay and cursor.
std::atomic< uint32_t > m_maxTextureSize
std::atomic< bool > m_shutdownRequested
std::atomic< RHI_BACKEND > m_backendType
void HandleFence(const RHI_CMD_FENCE &aCmd)
void HandleSwapchainCreate(const RHI_CMD_SWAPCHAIN_CREATE &aCmd)
bool writeUniform(RHI_BufferHandle &aUBO, RHI_BindGroupHandle &aBG, RHI_BindGroupLayoutHandle aLayout, const void *aData, size_t aSize)
Write a uniform block, making its buffer and bind group on first use.
std::atomic< bool > m_deviceLost
RHI_BindGroupHandle m_glyphBG
RHI_BindGroupHandle glyphBindGroup()
RHI_BufferHandle ReserveBufferHandle()
Reserve a handle without creating the GPU resource, so RHI_DEVICE_PROXY can hand it out on the UI thr...
RHI_TextureHandle ReserveTextureHandle()
RHI_RenderPassHandle m_geometryDepthDiscardRenderPass
As m_geometryRenderPass and m_geometryDepthLoadRenderPass, without storing depth nothing reads later.
GEOMETRY_RANGES
The ranges of a draw descriptor one geometry pass draws.
RENDER_THREAD(RHI_DEVICE_FACTORY aDeviceFactory)
void OnDeviceLost()
Stop drawing on a lost device.
void HandleFrameRequest(const RHI_CMD_FRAME_REQUEST &aCmd)
std::mutex m_deviceLostMutex
Held while a listener runs, so removing one waits for it to return.
void Shutdown()
Block until the render thread exits.
std::unordered_map< const void *, std::function< void()> > m_deviceLostListeners
std::condition_variable m_workCV
void recreateSwapchainAfterOutOfDate(WINDOW_STATE &aWS, bool aSurfaceLost=false)
Retire and recreate an out of date swapchain, and its surface too when aSurfaceLost.
std::unique_ptr< RHI_GAL_PIPELINES > m_pipelines
Shared by all windows and created once with the device.
void RenderGeometryInto(WINDOW_STATE &aWS, const FRAME_DRAW_DESC &aDesc, RHI_FramebufferHandle aFBO, bool aLogSummary, GEOMETRY_RANGES aRanges=GEOMETRY_RANGES::ALL, uint32_t aStaticDrawMargin=0)
bool RenderWindow(WINDOW_STATE &aWS)
std::unique_ptr< RHI_COMPOSITOR > m_compositor
RHI_RenderPassHandle m_geometryDepthLoadDiscardRenderPass
SYNC_QUEUE< RHI_CONTROL_COMMAND > m_controlQueue
bool SubmitControl(RHI_CONTROL_COMMAND aCmd)
void drawCursor(WINDOW_STATE &aWS)
Draw the cursor into the open composite pass.
bool Start()
Block until the render thread has created the device and its pipelines.
std::atomic< int > m_loopPhase
see GetLoopPhase()
void RenderGeometry(WINDOW_STATE &aWS)
RENDER_THREAD & operator=(const RENDER_THREAD &)=delete
std::vector< WINDOW_STATE * > m_activeWindowOrder
std::shared_ptr< const RHI_GLYPH_ATLAS_DATA > m_glyphAtlas
void destroyGlyphResources()
void DestroyWindowFBOs(WINDOW_STATE &aWS)
void destroyWindow(WINDOW_STATE &aWS)
Free a window's targets, uniforms, swapchain and surface.
Creates, uses and destroys GPU resources through one graphics API backend.
Synchronized, locking queue.
The Cairo implementation of the graphics abstraction layer.
std::function< std::unique_ptr< RHI_DEVICE >()> RHI_DEVICE_FACTORY
Creates the RHI_DEVICE.
std::variant< RHI_CMD_FRAME_REQUEST, RHI_CMD_SWAPCHAIN_CREATE, RHI_CMD_SWAPCHAIN_RESIZE, RHI_CMD_SWAPCHAIN_DESTROY, RHI_CMD_FENCE > RHI_CONTROL_COMMAND
One entry in the render thread control queue.
uint32_t RHI_WINDOW_ID
Routes control commands to a swapchain.
RHI_HANDLE< RHI_TAG_FRAMEBUFFER > RHI_FramebufferHandle
RHI_HANDLE< RHI_TAG_TEXTURE > RHI_TextureHandle
RHI_HANDLE< RHI_TAG_BUFFER > RHI_BufferHandle
RHI_HANDLE< RHI_TAG_BIND_GROUP > RHI_BindGroupHandle
RHI_HANDLE< RHI_TAG_BIND_GROUP_LAYOUT > RHI_BindGroupLayoutHandle
RHI_HANDLE< RHI_TAG_RENDER_PASS > RHI_RenderPassHandle
RHI_BACKEND
Identifies which graphics backend a device implements.
std::variant< RHI_GEOMETRY_UPLOAD, RHI_TEXTURE_UPLOAD, RHI_BUFFER_CREATE, RHI_TEXTURE_CREATE, RHI_BUFFER_DESTROY, RHI_TEXTURE_DESTROY > RHI_UPLOAD_COMMAND
One entry in the render thread upload queue.
GPU geometry of one frame, built by GAL_MODERN after EndDrawing() and passed through the FRAME_MAILBO...
Per-window state owned by the render thread.