diff --git a/librtt/Display/Rtt_Scene.cpp b/librtt/Display/Rtt_Scene.cpp index 0f280647a..bb379804d 100644 --- a/librtt/Display/Rtt_Scene.cpp +++ b/librtt/Display/Rtt_Scene.cpp @@ -284,23 +284,61 @@ Scene::Render( Renderer& renderer, PlatformSurface& rTarget, ProfilingEntryRAII* // When shader code depends on time, then frame is time-dependent. // So only set valid when frame is *in*dependent of time. + + // N.B. rather than requiring an explicit isTimeDependent flag to + // graphics.defineEffect(), a program is now queried about whether + // it has time-related state; this is captured in the ShaderResource's + // "uses time" flag, as before. The catch is that the resources in + // question first become available in either renderer.Swap() or + // renderer.Render(), too late for the check done here. if ( ! renderer.IsFrameTimeDependent() ) { fIsValid = true; } + // Some further analysis: + + // If DEFER_CREATION / DEFER_VK_CREATION are disabled, a new program's + // GPUResource will come into being in renderer.Swap(), and the shader + // objects for every ShaderVersion are immediately Create()'d. + + // Normally, however, we lazily create a given ProgramVersion's shader + // objects in its first Bind(), during renderer.Render(). + + // These operations, in either scenario, are strictly serial; the + // ShaderResource's flag may be set directly. (This would need rework + // if, say, a multithreaded renderer were adopted.) + + // The conventional logic will pick up the flag the next time around. + // However, the relevant time-dependent objects might be the only cause + // for the scene to be invalid. A compromise here is to give the scene + // a kick, explicitly invalidating it if ANY shader resource was just + // assigned the "uses time" flag. + + // The sanest CPU-side semantics--consistent with the isTimeDependent + // and ShaderResource flags--seems to be that if any ProgramVersion is + // time-dependent, all of them are interpreted this way. (This policy + // accounts for some corner cases, for instance only the fragment side + // might be time-dependent, but not be present in wireframe mode; this + // is cumbersome to convey precisely on the CPU side.) + ADD_ENTRY( "Scene: Issue Draw Commands" ); renderer.Swap(); // Swap back and front command buffers - + ADD_ENTRY( "Scene: Swap" ); renderer.Render(); // Render front command buffer // renderer.GetFrameStatistics().Log(); - + ADD_ENTRY( "Scene: Process Render Commands" ); + if ( renderer.AddedUsesTime() ) // n.b. clears the flag + { + Invalidate(); + } + rTarget.Flush(); ADD_ENTRY( "Scene: Flush" ); diff --git a/librtt/Display/Rtt_ShaderFactory.cpp b/librtt/Display/Rtt_ShaderFactory.cpp index cfd4a22c7..bedcf327c 100644 --- a/librtt/Display/Rtt_ShaderFactory.cpp +++ b/librtt/Display/Rtt_ShaderFactory.cpp @@ -686,7 +686,7 @@ ShaderFactory::BindTimeTransform(lua_State *L, int index, const SharedPtr< Shade { const char *func = TimeTransform::FindFunc( L, -1, "graphics.defineEffect()" ); - if (lua_isstring( L, -1 )) + if (func) { TimeTransform *transform = Rtt_NEW( fAllocator, TimeTransform ); @@ -762,11 +762,7 @@ ShaderFactory::InitializeBindings( lua_State *L, int shaderIndex, const SharedPt BindDetails( L, shaderIndex, resource ); BindShellTransform( L, shaderIndex, resource ); BindVertexExtension( L, shaderIndex, resource ); - - if (resource->UsesTime()) - { - BindTimeTransform( L, shaderIndex, resource ); - } + BindTimeTransform( L, shaderIndex, resource ); bool has_vertex_data = BindVertexDataMap( L, shaderIndex, resource ); if( has_vertex_data ) @@ -1018,11 +1014,6 @@ ShaderFactory::NewShaderBuiltin( ShaderTypes::Category category, const char *nam if (resource.NotNull()) { - lua_getfield( L, tableIndex, "isTimeDependent" ); - bool usesTime = lua_toboolean( L, -1 ) ? true : false; - resource->SetUsesTime( usesTime ); - lua_pop( L, 1 ); - Shader *prototype = NULL; prototype = NewShaderPrototype( L, tableIndex, resource ); result = (ShaderComposite*)prototype->Clone( fAllocator ); diff --git a/librtt/Display/Rtt_ShaderResource.cpp b/librtt/Display/Rtt_ShaderResource.cpp index 4669a51f8..483b276e2 100755 --- a/librtt/Display/Rtt_ShaderResource.cpp +++ b/librtt/Display/Rtt_ShaderResource.cpp @@ -27,58 +27,37 @@ namespace Rtt // ---------------------------------------------------------------------------- -bool -TimeTransform::Apply( Uniform *time, Real *old, U32 now ) +Real +TimeTransform::Apply( Real value ) const { - if (NULL != func && NULL != time) - { - if (timestamp != now) - { - timestamp = now; - - time->GetValue(cached); - - if (NULL != old) - { - *old = cached; - } - - func( &cached, arg1, arg2, arg3 ); - } - - time->SetValue(cached); - - return true; - } + Rtt_ASSERT( func ); - return false; + return func( value, arg1, arg2, arg3 ); } -static void -Modulo( Real *x, Real range, Real, Real ) +static Real +Modulo( Real x, Real range, Real, Real ) { - *x = fmod( *x, range ); // TODO?: Rtt_RealFmod + return fmod( x, range ); // TODO?: Rtt_RealFmod } -static void -PingPong( Real *x, Real range, Real, Real ) +static Real +PingPong( Real x, Real range, Real, Real ) { - Real pos = fmod( *x, Rtt_REAL_2 * range ); // TODO?: Rtt_RealFmod + Real pos = fmod( x, Rtt_REAL_2 * range ); // TODO?: Rtt_RealFmod if (pos > range) { pos = Rtt_REAL_2 * range - pos; } - *x = pos; + return pos; } -static void -Sine( Real *x, Real amplitude, Real speed, Real shift ) +static Real +Sine( Real x, Real amplitude, Real speed, Real shift ) { - Real t = *x; - - *x = amplitude * Rtt_RealSin( speed * t + shift ); + return amplitude * Rtt_RealSin( speed * x + shift ); } int @@ -105,7 +84,7 @@ TimeTransform::Push( lua_State *L ) const lua_pushnumber( L, (Rtt_REAL_2 * M_PI) / arg2 ); lua_setfield( L, -2, "period" ); lua_pushnumber( L, arg3 ); - lua_setfield( L, -2, "shift" ); + lua_setfield( L, -2, "phase" ); } else @@ -191,16 +170,16 @@ TimeTransform::SetFunc( lua_State *L, int arg, const char *what, const char *fna case 's': // sine { - Real amplitude = Rtt_REAL_1, period = Rtt_REAL_2 * M_PI, shift = Rtt_REAL_0; + Real amplitude = Rtt_REAL_1, period = Rtt_REAL_2 * M_PI, phase = Rtt_REAL_0; GetNumberArg( L, arg, &litude, fname, "amplitude", what ); GetPositiveNumberArg( L, arg, &period, fname, "period", what ); - GetNumberArg( L, arg, &shift, fname, "shift", what ); + GetNumberArg( L, arg, &phase, fname, "phase", what ); func = &Sine; arg1 = amplitude; arg2 = (Rtt_REAL_2 * M_PI) / period; - arg3 = shift; + arg3 = phase; } break; @@ -209,25 +188,6 @@ TimeTransform::SetFunc( lua_State *L, int arg, const char *what, const char *fna } } -bool -TimeTransform::Matches( const TimeTransform *xform1, const TimeTransform *xform2 ) -{ - if (xform1 == xform2) - { - return true; - } - - else if (NULL == xform1 || NULL == xform2) - { - return false; - } - - else - { - return xform1->func == xform2->func && xform1->arg1 == xform2->arg1 && xform1->arg2 == xform2->arg2 && xform1->arg3 == xform2->arg3; - } -} - const char* TimeTransform::FindFunc( lua_State *L, int arg, const char *what ) { @@ -465,6 +425,8 @@ ShaderResource::SetDefaultData( ShaderData *defaultData ) } } +bool ShaderResource::sAddedUsesTime; + // ---------------------------------------------------------------------------- } // namespace Rtt diff --git a/librtt/Display/Rtt_ShaderResource.h b/librtt/Display/Rtt_ShaderResource.h index 0567f1061..f00bd7391 100644 --- a/librtt/Display/Rtt_ShaderResource.h +++ b/librtt/Display/Rtt_ShaderResource.h @@ -35,23 +35,21 @@ class FormatExtensionList; struct TimeTransform { - typedef void (*Func)( Real *time, Real arg1, Real arg2, Real arg3 ); + typedef Real (*Func)( Real time, Real arg1, Real arg2, Real arg3 ); - TimeTransform() : func( NULL ), arg1( 0 ), arg2( 0 ), arg3( 0 ), timestamp( ~0 ) + TimeTransform() : func( NULL ), arg1( 0 ), arg2( 0 ), arg3( 0 ) { } - bool Apply( Uniform *time, Real *old, U32 now ); + Real Apply( Real value ) const; int Push( lua_State *L ) const; void SetDefault(); void SetFunc( lua_State *L, int arg, const char *what, const char *fname ); - static bool Matches( const TimeTransform *xform1, const TimeTransform *xform2 ); static const char* FindFunc( lua_State *L, int arg, const char *what ); Func func; - Real arg1, arg2, arg3, cached; - U32 timestamp; + Real arg1, arg2, arg3; }; // ---------------------------------------------------------------------------- @@ -139,6 +137,10 @@ class ShaderResource void SetProgramMod(ProgramMod mod, Program *program); Program *GetProgramMod(ProgramMod mod) const; + public: + static void SetAddedUsesTime( bool newValue ) { sAddedUsesTime = newValue; } + static bool GetAddedUsesTime() { return sAddedUsesTime; } + private: void Init(Program *defaultProgram); @@ -159,6 +161,8 @@ class ShaderResource TimeTransform *fTimeTransform; bool fUsesUniforms; bool fUsesTime; + + static bool sAddedUsesTime; // has ANY ShaderResource added the "uses time" flag? }; diff --git a/librtt/Display/Shader/kernel_filter_wobble_gl.lua b/librtt/Display/Shader/kernel_filter_wobble_gl.lua index f8bf41e2d..e7952d1fe 100644 --- a/librtt/Display/Shader/kernel_filter_wobble_gl.lua +++ b/librtt/Display/Shader/kernel_filter_wobble_gl.lua @@ -6,7 +6,11 @@ kernel.category = "filter" kernel.name = "wobble" -kernel.isTimeDependent = true +--kernel.isTimeDependent = true +kernel.timeTransform = { + func = "modulo", + range = ( 2 / 3 ) * math.pi -- cf. VertexKernel() +} kernel.vertexData = { @@ -23,6 +27,11 @@ kernel.vertex = [[ P_POSITION vec2 VertexKernel( P_POSITION vec2 position ) { + // sine is periodic, so we can use a short modular range + // at t = 0, sin( 3 * 0 ) = 0 (ignoring phase) + // this will next happen as sin( 2 * pi ) = 0, i.e. when 3 * t = 2 * pi + // rearranging, t = ( 2 / 3 ) * pi + position.y += sin( 3.0 * u_TotalTime + a_TexCoord.x ) * a_UserData.x * a_TexCoord.y; return position; diff --git a/librtt/Display/Shader/kernel_generator_marchingAnts_gl.lua b/librtt/Display/Shader/kernel_generator_marchingAnts_gl.lua index 96464526f..02903b3d7 100644 --- a/librtt/Display/Shader/kernel_generator_marchingAnts_gl.lua +++ b/librtt/Display/Shader/kernel_generator_marchingAnts_gl.lua @@ -6,7 +6,15 @@ kernel.category = "generator" kernel.name = "marchingAnts" -kernel.isTimeDependent = true +--kernel.isTimeDependent = true +kernel.timeTransform = { + func = "modulo", + + -- the pattern is very regular, thus being able to mod the time + -- the range is two bar lengths (on, then off), divided by speed + -- the content scaling cancels out + range = (6 + 6) / 16 +} kernel.unsupportedPlatforms = { diff --git a/librtt/Display/Shader/kernel_generator_random_gl.lua b/librtt/Display/Shader/kernel_generator_random_gl.lua index 7ad5c89bc..c2fd470a8 100644 --- a/librtt/Display/Shader/kernel_generator_random_gl.lua +++ b/librtt/Display/Shader/kernel_generator_random_gl.lua @@ -6,7 +6,8 @@ kernel.category = "generator" kernel.name = "random" -kernel.isTimeDependent = true +--kernel.isTimeDependent = true +kernel.timeTransform = { func = "modulo", range = 1 } kernel.fragment = [[ @@ -23,7 +24,7 @@ P_RANDOM float rand( P_RANDOM vec2 seed ) P_COLOR vec4 FragmentKernel( P_UV vec2 texCoord ) { #if FRAGMENT_SHADER_SUPPORTS_HIGHP - P_RANDOM float time = fract( u_TotalTime ); + P_RANDOM float time = u_TotalTime;//fract( u_TotalTime ); P_RANDOM float v0 = rand( vec2( ( time + texCoord.x ), ( time + texCoord.y ) ) ); diff --git a/librtt/Renderer/Rtt_CommandBuffer.cpp b/librtt/Renderer/Rtt_CommandBuffer.cpp index e71be04ef..cd6e11b3e 100644 --- a/librtt/Renderer/Rtt_CommandBuffer.cpp +++ b/librtt/Renderer/Rtt_CommandBuffer.cpp @@ -29,10 +29,8 @@ CommandBuffer::CommandBuffer( Rtt_Allocator* allocator ) fNumCommands( 0 ), fBytesAllocated( 0 ), fBytesUsed( 0 ), - fTimeTransform( NULL ), - fLastTimeTransform( NULL ), - fUsesTime( false ), - fDefaultTimeTransform( Rtt_NEW( allocator, TimeTransform ) ) + fDefaultTransformedTime( -1.f ), + fTimeTransform( NULL ) { } @@ -44,7 +42,7 @@ CommandBuffer::~CommandBuffer() delete [] fBuffer; } - Rtt_DELETE( fDefaultTimeTransform ); +// Rtt_DELETE( fDefaultTimeTransform ); } void @@ -77,30 +75,24 @@ CommandBuffer::WriteBytes( const void * value, size_t size ) } void -CommandBuffer::PrepareTimeTransforms( const TimeTransform* transform ) +CommandBuffer::PrepareTimeTransforms( float rawTime, const TimeTransform* transform ) { - *fDefaultTimeTransform = *transform; - fTimeTransform = NULL; - fLastTimeTransform = NULL; - fUsesTime = false; + + if ( transform->func ) + { + fDefaultTransformedTime = transform->Apply( rawTime ); + } + else + { + fDefaultTransformedTime = rawTime; + } } void CommandBuffer::AcquireTimeTransform( ShaderResource* resource ) { - fUsesTime = resource->UsesTime(); - - if (fUsesTime) - { - fLastTimeTransform = fTimeTransform; - fTimeTransform = resource->GetTimeTransform(); - - if ( NULL == fTimeTransform && NULL != fDefaultTimeTransform->func ) - { - fTimeTransform = fDefaultTimeTransform; - } - } + fTimeTransform = resource->GetTimeTransform(); } // ---------------------------------------------------------------------------- diff --git a/librtt/Renderer/Rtt_CommandBuffer.h b/librtt/Renderer/Rtt_CommandBuffer.h index e4257598e..02f4a7be6 100644 --- a/librtt/Renderer/Rtt_CommandBuffer.h +++ b/librtt/Renderer/Rtt_CommandBuffer.h @@ -122,7 +122,7 @@ class CommandBuffer virtual Real Execute( bool measureGPU ) = 0; public: - void PrepareTimeTransforms( const TimeTransform* transform ); + void PrepareTimeTransforms( float rawTime, const TimeTransform* transform ); protected: void AcquireTimeTransform( ShaderResource* resource ); @@ -139,10 +139,8 @@ class CommandBuffer U32 fNumCommands; U32 fBytesAllocated; U32 fBytesUsed; - TimeTransform* fDefaultTimeTransform; TimeTransform* fTimeTransform; - TimeTransform* fLastTimeTransform; - bool fUsesTime; + Real fDefaultTransformedTime; }; // ---------------------------------------------------------------------------- diff --git a/librtt/Renderer/Rtt_GLCommandBuffer.cpp b/librtt/Renderer/Rtt_GLCommandBuffer.cpp index e6d3547bc..80a11202d 100644 --- a/librtt/Renderer/Rtt_GLCommandBuffer.cpp +++ b/librtt/Renderer/Rtt_GLCommandBuffer.cpp @@ -54,6 +54,7 @@ namespace /*anonymous*/ kCommandBindProgram, kCommandBindInstancing, kCommandResolveVertexFormat, + kCommandBindTimeTransform, kCommandApplyUniformScalar, kCommandApplyUniformVec2, kCommandApplyUniformVec3, @@ -936,6 +937,7 @@ GLCommandBuffer::Execute( bool measureGPU ) Geometry::Vertex* instancingData = NULL; U32 currentAttributeCount = 0, instanceCount = 0; bool clearingDepth = false, clearingStencil = false; + TimeTransform* timeTransform = NULL; for( U32 i = 0; i < fNumCommands; ++i ) { @@ -1032,6 +1034,7 @@ GLCommandBuffer::Execute( bool measureGPU ) { fCurrentDrawVersion = Read(); GLProgram* program = Read(); + program->Bind( fCurrentDrawVersion ); program->GetExtraUniformsInfo( fCurrentDrawVersion, extraUniforms ); @@ -1119,9 +1122,18 @@ GLCommandBuffer::Execute( bool measureGPU ) instancingData = NULL; CHECK_ERROR_AND_BREAK; } + case kCommandBindTimeTransform: + { + timeTransform = Read(); + CHECK_ERROR_AND_BREAK; + } case kCommandApplyUniformScalar: { READ_UNIFORM_DATA( Real ); + if ( timeTransform && -1 != location ) + { + value = timeTransform->Apply( value ); + } glUniform1f( location, value ); DEBUG_PRINT( "Set Uniform: value=%f location=%i", value, location ); CHECK_ERROR_AND_BREAK; @@ -1164,6 +1176,10 @@ GLCommandBuffer::Execute( bool measureGPU ) case kCommandApplyUniformFromPointerScalar: { READ_UNIFORM_DATA_WITH_PROGRAM( Real ); + if ( timeTransform && -1 != location ) + { + value = timeTransform->Apply( value ); + } glUniform1f( location, value ); DEBUG_PRINT( "Set Uniform: value=%f location=%i", value, location ); CHECK_ERROR_AND_BREAK; @@ -1440,36 +1456,50 @@ GLCommandBuffer::Write( T value ) void GLCommandBuffer::ApplyUniforms( GPUResource* resource ) { GLProgram* glProgram = static_cast(resource); - + Uniform* timeUniform = fUniformUpdates[Uniform::kTotalTime].uniform; + + Rtt_ASSERT( timeUniform ); + + // This is the time value that gets transformed. If we do NOT need it + // on this call, that means we want the default transformed time, so + // we swap it into the uniform. In either case, the normal logic will + // take it from there. It is perfectly possible that another program + // WILL want to do a transform, so we restore the raw time at the end. Real rawTotalTime; - bool transformed = false; - - if (fUsesTime) - { - const UniformUpdate& time = fUniformUpdates[Uniform::kTotalTime]; - if (fTimeTransform) - { - transformed = fTimeTransform->Apply( time.uniform, &rawTotalTime, time.timestamp ); - } - if (transformed || !TimeTransform::Matches( fTimeTransform, fLastTimeTransform )) - { - fUniformUpdates[Uniform::kTotalTime].timestamp = glProgram->GetUniformTimestamp( Uniform::kTotalTime, fCurrentPrepVersion ) - 1; // force a refresh - } - } + + timeUniform->GetValue( rawTotalTime ); for( U32 i = 0; i < Uniform::kNumBuiltInVariables; ++i) { const UniformUpdate& update = fUniformUpdates[i]; if( update.uniform && update.timestamp != glProgram->GetUniformTimestamp( i, fCurrentPrepVersion ) ) { + if ( Uniform::kTotalTime == i ) + { + if ( fTimeTransform ) // keep the raw time; will be transformed if the uniform is bound + { + WRITE_COMMAND( kCommandBindTimeTransform ); + + Write( fTimeTransform ); + } + else + { + timeUniform->SetValue( fDefaultTransformedTime ); + } + } + ApplyUniform( resource, i ); + + if ( Uniform::kTotalTime == i && fTimeTransform ) // uniform might be absent, so unbind here + { + WRITE_COMMAND( kCommandBindTimeTransform ); + + Write( NULL ); + } } } - if (transformed) // restore raw value (lets us avoid a redundant variable; will also be in place for un-transformed time dependencies) - { - fUniformUpdates[Uniform::kTotalTime].uniform->SetValue(rawTotalTime); - } + timeUniform->SetValue( rawTotalTime ); } void GLCommandBuffer::ApplyUniform( GPUResource* resource, U32 index ) diff --git a/librtt/Renderer/Rtt_GLProgram.cpp b/librtt/Renderer/Rtt_GLProgram.cpp index 437697979..91805e275 100644 --- a/librtt/Renderer/Rtt_GLProgram.cpp +++ b/librtt/Renderer/Rtt_GLProgram.cpp @@ -38,6 +38,8 @@ // To reduce memory consumption and startup cost, defer the // creation of GL shaders and programs until they're needed. // Depending on usage, this could result in framerate dips. + +// TODO: verify for updated "uses time" logic, cf. note in Rtt_Scene.cpp #define DEFER_CREATION 1 // ---------------------------------------------------------------------------- @@ -148,11 +150,17 @@ GLProgram::Create( CPUResource* resource ) Rtt_ASSERT( CPUResource::kProgram == resource->GetType() ); fResource = resource; - + #if !DEFER_CREATION + bool usesTime = false; for( U32 i = 0; i < kMaximumMaskCount + 1; ++i ) { Create( fData[i], i ); + + if ( !usesTime && fData[i].HasTime() ) + { + usesTime = true; + } } #endif @@ -160,6 +168,16 @@ GLProgram::Create( CPUResource* resource ) Program* program = static_cast( fResource ); ShaderResource* shaderResource = program->GetShaderResource(); + + #if !DEFER_CREATION + if ( usesTime ) + { + shaderResource->SetUsesTime( true ); + + ShaderResource::SetAddedUsesTime( true ); + } + #endif + const CoronaShellTransform * transform = shaderResource->GetShellTransform(); if (transform && transform->cleanup) @@ -218,6 +236,15 @@ GLProgram::Bind( Program::Version version ) if( !data.fProgram ) { Create( version, data ); + + if ( fData[version].HasTime() ) + { + Program* program = (Program*)fResource; + + program->GetShaderResource()->SetUsesTime( true ); + + ShaderResource::SetAddedUsesTime( true ); + } } #endif diff --git a/librtt/Renderer/Rtt_GLProgram.h b/librtt/Renderer/Rtt_GLProgram.h index ec3fffe49..02d1b97f3 100644 --- a/librtt/Renderer/Rtt_GLProgram.h +++ b/librtt/Renderer/Rtt_GLProgram.h @@ -73,6 +73,12 @@ class GLProgram : public GPUResource // Metadata int fHeaderNumLines; + + bool HasTime() const + { + return -1 != fUniformLocations[Uniform::kTotalTime] || + -1 != fUniformLocations[Uniform::kDeltaTime]; + } }; void Create( Program::Version version, VersionData& data ); diff --git a/librtt/Renderer/Rtt_Renderer.cpp b/librtt/Renderer/Rtt_Renderer.cpp index 419d78150..270525a83 100644 --- a/librtt/Renderer/Rtt_Renderer.cpp +++ b/librtt/Renderer/Rtt_Renderer.cpp @@ -264,7 +264,7 @@ Renderer::BeginFrame( Real totalTime, Real deltaTime, const TimeTransform *defTi fBackCommandBuffer->BindUniform( fDeltaTime, Uniform::kDeltaTime ); fBackCommandBuffer->ClearUserUniforms(); - fBackCommandBuffer->PrepareTimeTransforms( defTimeTransform ); + fBackCommandBuffer->PrepareTimeTransforms( totalTime, defTimeTransform ); fBackCommandBuffer->SetBlendEnabled( fPrevious.fBlendEquation != RenderTypes::kDisabledEquation ); fBackCommandBuffer->SetBlendFunction( fPrevious.fBlendMode ); @@ -2055,6 +2055,16 @@ Renderer::GetVersionCode( bool addingMask ) const } } +bool +Renderer::AddedUsesTime() +{ + bool addedUsesTime = ShaderResource::GetAddedUsesTime(); + + ShaderResource::SetAddedUsesTime( false ); + + return addedUsesTime; +} + void Renderer::MergeVertexData( Geometry::Vertex** destination, const Geometry::Vertex* mainSrc, const Geometry::Vertex* extensionSrc, int index, int extraCount ) { diff --git a/librtt/Renderer/Rtt_Renderer.h b/librtt/Renderer/Rtt_Renderer.h index dc34e4beb..416165d68 100644 --- a/librtt/Renderer/Rtt_Renderer.h +++ b/librtt/Renderer/Rtt_Renderer.h @@ -321,6 +321,9 @@ class Renderer public: int GetVersionCode( bool addingMask ) const; + public: + bool AddedUsesTime(); + protected: Rtt_Allocator* fAllocator; diff --git a/librtt/Renderer/Rtt_VulkanCommandBuffer.cpp b/librtt/Renderer/Rtt_VulkanCommandBuffer.cpp index 493bc95c8..ef6e7174e 100644 --- a/librtt/Renderer/Rtt_VulkanCommandBuffer.cpp +++ b/librtt/Renderer/Rtt_VulkanCommandBuffer.cpp @@ -41,6 +41,7 @@ namespace /*anonymous*/ kCommandFetchRenderState, kCommandBindTexture, kCommandBindProgram, + kCommandBindTimeTransform, kCommandApplyPushConstantScalar, kCommandApplyPushConstantVec2, kCommandApplyPushConstantVec3, @@ -786,6 +787,7 @@ VulkanCommandBuffer::Execute( bool measureGPU ) renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + TimeTransform* timeTransform = NULL; VulkanGeometry * geometry = NULL; VulkanFrameBufferObject * fbo = NULL; U32 stages = 0U; @@ -952,10 +954,19 @@ VulkanCommandBuffer::Execute( bool measureGPU ) DEBUG_PRINT( "Bind Program: program=%p version=%i", program, fCurrentDrawVersion ); CHECK_ERROR_AND_BREAK; } + case kCommandBindTimeTransform: + { + timeTransform = Read(); + CHECK_ERROR_AND_BREAK; + } case kCommandApplyPushConstantScalar: { U32 offset = Read(); Real value = Read(); + if ( timeTransform ) + { + value = timeTransform->Apply( value ); + } pushConstants.Write( offset, &value, sizeof( Real ) ); DEBUG_PRINT( "Set Push Constant: value=%f location=%i", value, offset ); CHECK_ERROR_AND_BREAK; @@ -1021,6 +1032,10 @@ VulkanCommandBuffer::Execute( bool measureGPU ) { READ_UNIFORM_DATA( Real ); U32 index = Read(); + if ( timeTransform ) + { + value = timeTransform->Apply( value ); + } U8 * data = PointToUniform( index, location.fOffset ); memcpy( data, &value, sizeof( Real ) ); DEBUG_PRINT( "Set Uniform: value=%f location=%i", value, location.fOffset ); @@ -1081,6 +1096,10 @@ VulkanCommandBuffer::Execute( bool measureGPU ) READ_UNIFORM_DATA_WITH_PROGRAM( Real ); if (location.IsValid()) { + if ( timeTransform ) + { + value = timeTransform->Apply( value ); + } pushConstants.Write( location.fOffset, &value, sizeof( Real ) ); } DEBUG_PRINT( "Set Push Constant: value=%f location=%i", value, location.fOffset ); @@ -1159,6 +1178,10 @@ VulkanCommandBuffer::Execute( bool measureGPU ) case kCommandApplyUniformFromPointerScalar: { READ_UNIFORM_DATA_WITH_PROGRAM( Real ); + if ( timeTransform ) + { + value = timeTransform->Apply( value ); + } if (program->HavePushConstantUniforms() && Descriptor::IsPushConstant( index, true )) { pushConstants.Write( location.fOffset, &value, sizeof( Real ) ); @@ -1781,37 +1804,47 @@ VulkanCommandBuffer::Write( T value ) void VulkanCommandBuffer::ApplyUniforms( GPUResource* resource ) { - Real rawTotalTime; - bool transformed = false; - VulkanProgram* vulkanProgram = static_cast< VulkanProgram * >( resource ); - - if (fUsesTime) - { - const UniformUpdate& time = fUniformUpdates[Uniform::kTotalTime]; - if (fTimeTransform) - { - transformed = fTimeTransform->Apply( time.uniform, &rawTotalTime, time.timestamp ); - } - if (transformed || !TimeTransform::Matches( fTimeTransform, fLastTimeTransform )) - { - fUniformUpdates[Uniform::kTotalTime].timestamp = vulkanProgram->GetUniformTimestamp( Uniform::kTotalTime, fCurrentPrepVersion ) - 1; // force a refresh - } - } + Uniform* timeUniform = fUniformUpdates[Uniform::kTotalTime].uniform; + + Rtt_ASSERT( timeUniform ); + + // See GLCommandBuffer::ApplyUniforms() + Real rawTotalTime; + + timeUniform->GetValue( rawTotalTime ); for( U32 i = 0; i < Uniform::kNumBuiltInVariables; ++i) { const UniformUpdate& update = fUniformUpdates[i]; if( update.uniform && update.timestamp != vulkanProgram->GetUniformTimestamp( i, fCurrentPrepVersion ) ) - { + { + if ( Uniform::kTotalTime == i ) + { + if ( fTimeTransform ) // keep the raw time; will be transformed if the uniform is bound + { + WRITE_COMMAND( kCommandBindTimeTransform ); + + Write( fTimeTransform ); + } + else + { + timeUniform->SetValue( fDefaultTransformedTime ); + } + } + ApplyUniform( *vulkanProgram, i ); + + if ( Uniform::kTotalTime == i && fTimeTransform ) // uniform might be absent, so unbind here + { + WRITE_COMMAND( kCommandBindTimeTransform ); + + Write( NULL ); + } } } - if (transformed) // restore raw value (lets us avoid a redundant variable; will also be in place for un-transformed time dependencies) - { - fUniformUpdates[Uniform::kTotalTime].uniform->SetValue(rawTotalTime); - } + timeUniform->SetValue( rawTotalTime ); } void VulkanCommandBuffer::ApplyPushConstant( Uniform * uniform, size_t offset, const size_t * translationOffset, VulkanProgram * program, U32 index ) diff --git a/librtt/Renderer/Rtt_VulkanProgram.cpp b/librtt/Renderer/Rtt_VulkanProgram.cpp index b3002a3ae..3f8a0d11d 100644 --- a/librtt/Renderer/Rtt_VulkanProgram.cpp +++ b/librtt/Renderer/Rtt_VulkanProgram.cpp @@ -21,6 +21,9 @@ #endif #include "Core/Rtt_Assert.h" + +#include "Display/Rtt_ShaderResource.h" + #include #include #include @@ -44,6 +47,8 @@ // To reduce memory consumption and startup cost, defer the // creation of Vulkan shaders and programs until they're needed. // Depending on usage, this could result in framerate dips. + +// TODO: verify for updated "uses time" logic, cf. note in Rtt_Scene.cpp #define DEFER_VK_CREATION 1 // ---------------------------------------------------------------------------- @@ -155,9 +160,27 @@ VulkanProgram::Create( CPUResource* resource ) fResource = resource; #if !DEFER_VK_CREATION + bool usesTime = false; for( U32 i = 0; i < kMaximumMaskCount + 1; ++i ) { Create( fData[i], i ); + + if ( !usesTime && fData[i].HasTime() ) + { + usesTime = true; + } + } + #endif + + Program* program = static_cast( fResource ); + ShaderResource* shaderResource = program->GetShaderResource(); + + #if !DEFER_VK_CREATION + if ( usesTime ) + { + shaderResource->SetUsesTime( true ); + + ShaderResource::SetAddedUsesTime( true ); } #endif } @@ -200,6 +223,15 @@ VulkanProgram::Bind( VulkanRenderer & renderer, Program::Version version ) if( !data.fAttemptedCreation ) { Create( version, data ); + + if ( fData[version].HasTime() ) + { + Program* program = (Program*)fResource; + + program->GetShaderResource()->SetUsesTime( true ); + + ShaderResource::SetAddedUsesTime( true ); + } } #endif @@ -1658,4 +1690,4 @@ VulkanProgram::CleanUpCompiler( shaderc_compiler_t compiler, shaderc_compile_opt // ---------------------------------------------------------------------------- -#undef VP_STR_AND_LEN \ No newline at end of file +#undef VP_STR_AND_LEN diff --git a/librtt/Renderer/Rtt_VulkanProgram.h b/librtt/Renderer/Rtt_VulkanProgram.h index 6acc12f3f..e509889dd 100644 --- a/librtt/Renderer/Rtt_VulkanProgram.h +++ b/librtt/Renderer/Rtt_VulkanProgram.h @@ -134,6 +134,12 @@ class VulkanProgram : public GPUResource // Metadata int fHeaderNumLines; + + bool HasTime() const + { + return fUniformLocations[Uniform::kTotalTime].IsValid() || + fUniformLocations[Uniform::kDeltaTime].IsValid(); + } }; void Create( Program::Version version, VersionData& data );