using Godot; using System.Collections.Generic; namespace Rokojori { public partial class RDContext { protected RenderingDevice _renderingDevice; public RenderingDevice renderingDevice => _renderingDevice; protected bool _localRenderingDevice; public bool isLocalRenderingDevice => _localRenderingDevice; protected RDShader _shader; public RDShader shader => _shader; protected RDPipeline _pipeline; public RDPipeline pipeline => _pipeline; public static RDContext Local() { var ctx = new RDContext(); ctx.Initialize( true ); return ctx; } public void Initialize( bool local = false) { _localRenderingDevice = local; _renderingDevice = local ? RenderingServer.Singleton.CreateLocalRenderingDevice(): RenderingServer.Singleton.GetRenderingDevice(); if ( _renderingDevice == null ) { Error( "Could not initialize rendering device" ); } } protected int _view = -1; public int view => _view; protected int _effectCallbackType; public int effectCallbackType => _effectCallbackType; protected RenderData _renderData; public RenderData renderData => _renderData; protected RenderSceneBuffersRD _sceneBuffers; public RenderSceneBuffersRD sceneBuffers => _sceneBuffers; protected RenderSceneDataRD _sceneData; public RenderSceneDataRD sceneData => _sceneData; protected Vector3I _groups; public Vector3I groups => _groups; public Vector2I internalSize => _sceneBuffers.GetInternalSize(); public RDTexture GetScreenColorTexture() { return RDTexture.Color( this ); } public RDTexture GetScreenDepthTexture() { return RDTexture.Depth( this ); } public void SetProgram( RDProgram p ) { SetShaderAndPipeline( p.shader, p.pipeline ); } public void SetProgramFromPath( string path ) { Verbose( "Creating program:", path ); var program = RDProgram.FromPath( this, path ); SetProgram( program ); } public void SetShaderAndPipeline( RDShader shader, RDPipeline pipeline ) { if ( shader == null || pipeline == null ) { _shader = null; _pipeline = null; Error( "Shader Pipeline is null", shader, pipeline ); return; } Verbose( "Set Shader Pipeline", shader, pipeline ); _shader = shader; _pipeline = pipeline; } public void AssignScreenColorTexture( RDSampler sampler = null, int setIndex = -1 ) { AssignTexture( GetScreenColorTexture(), sampler, setIndex ); } public void AssignScreenDepthTexture( RDSampler sampler = null, int setIndex = -1 ) { AssignTexture( GetScreenDepthTexture(), sampler, setIndex ); } public void AssignTexture( RDTexture texture, RDSampler sampler = null, int setIndex = -1 ) { // effect.Verbose( "Incoming Uniform Index", setIndex ); if ( setIndex == -1 ) { setIndex = _uniformSets.Count; } // effect.Verbose( "Set Uniform Index", setIndex ); if ( sampler == null ) { // effect.Verbose( "Adding Image" ); AddUniformSet( RDUniformSet.Image( this, texture, setIndex ) ); } else { // effect.Verbose( "Adding Sampler" ); AddUniformSet( RDUniformSet.Sampler( this, sampler,texture, setIndex ) ); } } List _uniformSets = new List(); public RDPushConstants pushConstants; public void AddUniformSet( RDUniformSet uniformSet ) { _uniformSets.Add( uniformSet ); } public void CreateUniformaSet( params RDUniform[] uniforms ) { var setIndex = _uniformSets.Count; _CreateUniformSetRid( setIndex, uniforms ); } public Rid _CreateUniformSetRid( int index, params RDUniform[] uniforms ) { var array = new Godot.Collections.Array(); array.AddRange( uniforms ); if ( ! isLocalRenderingDevice ) { return UniformSetCacheRD.GetCache( shader.rid, (uint) index, array ); } else { return renderingDevice.UniformSetCreate( array, shader.rid, (uint) index ); } } public void Clear() { _uniformSets.Clear(); pushConstants = null; } public Vector2I computeSize = new Vector2I( 512, 512 ); public Vector2I GetComputeSize() { if ( _sceneBuffers != null ) { return _sceneBuffers.GetInternalSize(); } return computeSize; } public void SetComputeGroups( Vector3I groups ) { this._groups = groups; } public void CalculateSceneComputeGroups( int groupSize ) { var size = GetComputeSize(); CalculateComputeGroups( new Vector3I( groupSize, groupSize, 0 ), size ); } public void CalculateSceneComputeGroups( Vector3I groupSize ) { var size = GetComputeSize(); CalculateComputeGroups( groupSize, size ); } public void CalculateComputeGroups( int groupSize, Vector2I size ) { CalculateComputeGroups( new Vector3I( groupSize, groupSize, 0 ), size ); } public void CalculateComputeGroups( Vector3I groupSize, Vector2I size ) { var xGroups = Mathf.CeilToInt( size.X / (float) groupSize.X ); var yGroups = groupSize.Y == 0 ? 1 : Mathf.CeilToInt( size.Y / (float) groupSize.Y ); var zGroups = 1; SetComputeGroups( new Vector3I( xGroups, yGroups, zGroups ) ); } public void Submit() { if ( ! isLocalRenderingDevice ) { Error( "You can only submit or sync in non-local rendering devices" ); return; } renderingDevice.Submit(); } public void Sync() { if ( ! isLocalRenderingDevice ) { Error( "You can only submit or sync in non-local rendering devices" ); return; } renderingDevice.Sync(); } public void SubmitAndSync() { if ( ! isLocalRenderingDevice ) { Error( "You can only submit or sync in non-local rendering devices" ); return; } Submit(); Sync(); } public void ProcessComputeProgram() { try { var computeList = RDComputeList.Begin( _renderingDevice ); computeList.BindPipeline( pipeline ); _uniformSets.ForEach( ( u )=> { computeList.BindUniformSet( u, u.setIndex ); } ); if ( pushConstants != null ) { computeList.SetPushConstants( pushConstants ); } computeList.Dispatch( groups ); computeList.End(); } catch( System.Exception e ) { Error( e ); } Clear(); } public void SetRenderData( RenderData renderData, RenderSceneBuffersRD buffers, RenderSceneDataRD sceneData ) { this._renderData = renderData; this._sceneBuffers = buffers; this._sceneData = sceneData; } public void SetView( int view ) { this._view = view; } } }