Text fix
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user