This commit is contained in:
2026-05-20 17:04:03 +10:00
parent e43ac21b2f
commit a9eeed30cf
8 changed files with 58 additions and 23 deletions

View File

@@ -344,7 +344,8 @@ void RenderThread::TryCommitReadyRuntimeShader(RuntimeRenderScene& runtimeRender
std::string commitError;
if (TryTakePendingRenderLayers(layers))
{
if (!runtimeRenderScene.CommitRenderLayers(layers, commitError))
bool structuralChange = false;
if (!runtimeRenderScene.CommitRenderLayers(layers, commitError, &structuralChange))
{
RenderCadenceCompositor::TryLog(
RenderCadenceCompositor::LogLevel::Error,
@@ -354,11 +355,14 @@ void RenderThread::TryCommitReadyRuntimeShader(RuntimeRenderScene& runtimeRender
return;
}
RenderCadenceCompositor::TryLog(
RenderCadenceCompositor::LogLevel::Log,
"render-thread",
"Runtime render layer snapshot committed.");
mShaderBuildsCommitted.fetch_add(1, std::memory_order_relaxed);
if (structuralChange)
{
RenderCadenceCompositor::TryLog(
RenderCadenceCompositor::LogLevel::Log,
"render-thread",
"Runtime render layer snapshot committed.");
mShaderBuildsCommitted.fetch_add(1, std::memory_order_relaxed);
}
return;
}

View File

@@ -20,9 +20,10 @@ bool RuntimeRenderScene::StartPrepareWorker(std::unique_ptr<HiddenGlWindow> shar
return mPrepareWorker.Start(std::move(sharedWindow), error);
}
bool RuntimeRenderScene::CommitRenderLayers(const std::vector<RenderCadenceCompositor::RuntimeRenderLayerModel>& layers, std::string& error)
bool RuntimeRenderScene::CommitRenderLayers(const std::vector<RenderCadenceCompositor::RuntimeRenderLayerModel>& layers, std::string& error, bool* structuralChange)
{
ConsumePreparedPrograms();
bool changedStructure = false;
std::vector<std::string> nextOrder;
std::vector<RenderCadenceCompositor::RuntimeRenderLayerModel> layersToPrepare;
@@ -49,6 +50,7 @@ bool RuntimeRenderScene::CommitRenderLayers(const std::vector<RenderCadenceCompo
}
ReleasePendingPrograms(*layerIt);
layerIt = mLayers.erase(layerIt);
changedStructure = true;
}
for (const RenderCadenceCompositor::RuntimeRenderLayerModel& layer : layers)
@@ -66,6 +68,7 @@ bool RuntimeRenderScene::CommitRenderLayers(const std::vector<RenderCadenceCompo
next.layerId = layer.id;
mLayers.push_back(std::move(next));
program = &mLayers.back();
changedStructure = true;
}
bool hasReadyPass = false;
@@ -93,11 +96,16 @@ bool RuntimeRenderScene::CommitRenderLayers(const std::vector<RenderCadenceCompo
program->shaderId = layer.shaderId;
program->pendingFingerprint = fingerprint;
layersToPrepare.push_back(layer);
changedStructure = true;
}
if (mLayerOrder != nextOrder)
changedStructure = true;
mLayerOrder = std::move(nextOrder);
if (!layersToPrepare.empty())
mPrepareWorker.Submit(layersToPrepare);
if (structuralChange)
*structuralChange = changedStructure;
error.clear();
return true;
}

View File

@@ -20,7 +20,7 @@ public:
~RuntimeRenderScene();
bool StartPrepareWorker(std::unique_ptr<HiddenGlWindow> sharedWindow, std::string& error);
bool CommitRenderLayers(const std::vector<RenderCadenceCompositor::RuntimeRenderLayerModel>& layers, std::string& error);
bool CommitRenderLayers(const std::vector<RenderCadenceCompositor::RuntimeRenderLayerModel>& layers, std::string& error, bool* structuralChange = nullptr);
bool HasLayers();
void RenderFrame(uint64_t frameIndex, unsigned width, unsigned height, GLuint videoInputTexture = 0);
void ShutdownGl();

View File

@@ -61,6 +61,7 @@ bool RuntimeShaderRenderer::CommitPreparedProgram(RuntimePreparedShaderProgram&
DestroyProgram();
return false;
}
mTextTextures.RefreshTextTextures();
return true;
}
@@ -70,6 +71,7 @@ void RuntimeShaderRenderer::UpdateArtifactState(const RuntimeShaderArtifact& art
mArtifact.parameterValues = artifact.parameterValues;
mArtifact.message = artifact.message;
mTextTextures.UpdateArtifactState(artifact);
mTextTextures.RefreshTextTextures();
}
bool RuntimeShaderRenderer::BuildPreparedProgram(

View File

@@ -88,6 +88,7 @@ bool RuntimeTextTextureCache::Configure(const RuntimeShaderArtifact& artifact, s
TextTexture texture;
texture.parameterId = definition.id;
texture.fontId = definition.fontId;
texture.maxLength = definition.maxLength == 0 ? 64 : definition.maxLength;
mTextTextures.push_back(std::move(texture));
}
@@ -101,14 +102,21 @@ void RuntimeTextTextureCache::UpdateArtifactState(const RuntimeShaderArtifact& a
mArtifact.parameterValues = artifact.parameterValues;
}
void RuntimeTextTextureCache::RefreshTextTextures()
{
for (TextTexture& textTexture : mTextTextures)
{
EnsureTextTexture(textTexture);
}
}
void RuntimeTextTextureCache::BindTextTextures(GLuint program)
{
for (std::size_t index = 0; index < mTextTextures.size(); ++index)
{
TextTexture& textTexture = mTextTextures[index];
if (!EnsureTextTexture(textTexture))
const TextTexture& textTexture = mTextTextures[index];
if (textTexture.texture == 0)
continue;
glActiveTexture(GL_TEXTURE0 + kFirstTextTextureUnit + static_cast<GLuint>(index));
glBindTexture(GL_TEXTURE_2D, textTexture.texture);
}
@@ -318,21 +326,32 @@ bool RuntimeTextTextureCache::EnsureTextTexture(TextTexture& texture)
unsigned width = 0;
unsigned height = 0;
std::vector<unsigned char> pixels = ComposeTextMask(*atlas, text, width, height);
std::vector<unsigned char> pixels = ComposeTextMask(*atlas, texture, text, width, height);
if (pixels.empty() || width == 0 || height == 0)
return false;
if (texture.texture == 0)
glGenTextures(1, &texture.texture);
GLint previousUnpackAlignment = 4;
glGetIntegerv(GL_UNPACK_ALIGNMENT, &previousUnpackAlignment);
glBindTexture(GL_TEXTURE_2D, texture.texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, static_cast<GLsizei>(width), static_cast<GLsizei>(height), 0, GL_RED, GL_UNSIGNED_BYTE, pixels.data());
if (texture.width != width || texture.height != height)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, static_cast<GLsizei>(width), static_cast<GLsizei>(height), 0, GL_RED, GL_UNSIGNED_BYTE, pixels.data());
}
else
{
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, static_cast<GLsizei>(width), static_cast<GLsizei>(height), GL_RED, GL_UNSIGNED_BYTE, pixels.data());
}
glBindTexture(GL_TEXTURE_2D, 0);
glPixelStorei(GL_UNPACK_ALIGNMENT, previousUnpackAlignment);
glActiveTexture(GL_TEXTURE0);
texture.cachedText = text;
texture.width = width;
@@ -340,7 +359,7 @@ bool RuntimeTextTextureCache::EnsureTextTexture(TextTexture& texture)
return texture.texture != 0;
}
std::vector<unsigned char> RuntimeTextTextureCache::ComposeTextMask(const Atlas& atlas, const std::string& text, unsigned& width, unsigned& height) const
std::vector<unsigned char> RuntimeTextTextureCache::ComposeTextMask(const Atlas& atlas, const TextTexture& texture, const std::string& text, unsigned& width, unsigned& height) const
{
double advance = 0.0;
for (unsigned char character : text)
@@ -350,7 +369,8 @@ std::vector<unsigned char> RuntimeTextTextureCache::ComposeTextMask(const Atlas&
advance += glyphIt->second.advance;
}
width = (std::max)(1u, static_cast<unsigned>(std::ceil(advance * kFontPixelsPerEm)) + kTextTexturePadding * 2u);
const unsigned fixedWidth = static_cast<unsigned>(std::ceil(static_cast<double>(texture.maxLength) * kFontPixelsPerEm * 0.9)) + kTextTexturePadding * 2u;
width = (std::max)(fixedWidth, static_cast<unsigned>(std::ceil(advance * kFontPixelsPerEm)) + kTextTexturePadding * 2u);
height = kTextTextureHeight;
std::vector<unsigned char> mask(static_cast<std::size_t>(width) * height, 0);

View File

@@ -17,6 +17,7 @@ public:
bool Configure(const RuntimeShaderArtifact& artifact, std::string& error);
void UpdateArtifactState(const RuntimeShaderArtifact& artifact);
void RefreshTextTextures();
void BindTextTextures(GLuint program);
void ShutdownGl();
@@ -57,13 +58,14 @@ private:
GLuint texture = 0;
unsigned width = 0;
unsigned height = 0;
unsigned maxLength = 64;
};
bool LoadAtlas(const RenderCadenceCompositor::FontAtlasBuildOutput& output, Atlas& atlas, std::string& error) const;
bool LoadAtlasJson(const RenderCadenceCompositor::FontAtlasBuildOutput& output, Atlas& atlas, std::string& error) const;
bool LoadAtlasImage(const RenderCadenceCompositor::FontAtlasBuildOutput& output, Atlas& atlas, std::string& error) const;
bool EnsureTextTexture(TextTexture& texture);
std::vector<unsigned char> ComposeTextMask(const Atlas& atlas, const std::string& text, unsigned& width, unsigned& height) const;
std::vector<unsigned char> ComposeTextMask(const Atlas& atlas, const TextTexture& texture, const std::string& text, unsigned& width, unsigned& height) const;
const Atlas* FindAtlas(const std::string& fontId) const;
static const ShaderParameterValue* FindParameterValue(const RuntimeShaderArtifact& artifact, const std::string& parameterId);
static std::string DefaultTextValue(const RuntimeShaderArtifact& artifact, const std::string& parameterId);

View File

@@ -359,7 +359,7 @@ export function ParameterField({ layer, parameter, onParameterChange }) {
placeholder={parameter.defaultValue ? `Default: ${parameter.defaultValue}` : ""}
value={draftValue ?? ""}
onFocus={beginInteraction}
onChange={(event) => sendValue(event.target.value)}
onChange={(event) => scheduleSendValue(event.target.value, false, 350)}
onBlur={endInteraction}
/>
</div>

View File

@@ -82,7 +82,7 @@ export function useThrottledParameterValue(parameter, onParameterChange) {
}
};
const scheduleSendValue = (value, immediate = false) => {
const scheduleSendValue = (value, immediate = false, throttleMs = 90) => {
setDraftValue(value);
latestDraftRef.current = value;
isDirtyRef.current = true;
@@ -93,7 +93,6 @@ export function useThrottledParameterValue(parameter, onParameterChange) {
}
const now = Date.now();
const throttleMs = 90;
const elapsed = now - lastSentAtRef.current;
if (immediate || elapsed >= throttleMs) {