Text fix
This commit is contained in:
@@ -344,7 +344,8 @@ void RenderThread::TryCommitReadyRuntimeShader(RuntimeRenderScene& runtimeRender
|
|||||||
std::string commitError;
|
std::string commitError;
|
||||||
if (TryTakePendingRenderLayers(layers))
|
if (TryTakePendingRenderLayers(layers))
|
||||||
{
|
{
|
||||||
if (!runtimeRenderScene.CommitRenderLayers(layers, commitError))
|
bool structuralChange = false;
|
||||||
|
if (!runtimeRenderScene.CommitRenderLayers(layers, commitError, &structuralChange))
|
||||||
{
|
{
|
||||||
RenderCadenceCompositor::TryLog(
|
RenderCadenceCompositor::TryLog(
|
||||||
RenderCadenceCompositor::LogLevel::Error,
|
RenderCadenceCompositor::LogLevel::Error,
|
||||||
@@ -354,11 +355,14 @@ void RenderThread::TryCommitReadyRuntimeShader(RuntimeRenderScene& runtimeRender
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderCadenceCompositor::TryLog(
|
if (structuralChange)
|
||||||
RenderCadenceCompositor::LogLevel::Log,
|
{
|
||||||
"render-thread",
|
RenderCadenceCompositor::TryLog(
|
||||||
"Runtime render layer snapshot committed.");
|
RenderCadenceCompositor::LogLevel::Log,
|
||||||
mShaderBuildsCommitted.fetch_add(1, std::memory_order_relaxed);
|
"render-thread",
|
||||||
|
"Runtime render layer snapshot committed.");
|
||||||
|
mShaderBuildsCommitted.fetch_add(1, std::memory_order_relaxed);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,9 +20,10 @@ bool RuntimeRenderScene::StartPrepareWorker(std::unique_ptr<HiddenGlWindow> shar
|
|||||||
return mPrepareWorker.Start(std::move(sharedWindow), error);
|
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();
|
ConsumePreparedPrograms();
|
||||||
|
bool changedStructure = false;
|
||||||
|
|
||||||
std::vector<std::string> nextOrder;
|
std::vector<std::string> nextOrder;
|
||||||
std::vector<RenderCadenceCompositor::RuntimeRenderLayerModel> layersToPrepare;
|
std::vector<RenderCadenceCompositor::RuntimeRenderLayerModel> layersToPrepare;
|
||||||
@@ -49,6 +50,7 @@ bool RuntimeRenderScene::CommitRenderLayers(const std::vector<RenderCadenceCompo
|
|||||||
}
|
}
|
||||||
ReleasePendingPrograms(*layerIt);
|
ReleasePendingPrograms(*layerIt);
|
||||||
layerIt = mLayers.erase(layerIt);
|
layerIt = mLayers.erase(layerIt);
|
||||||
|
changedStructure = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const RenderCadenceCompositor::RuntimeRenderLayerModel& layer : layers)
|
for (const RenderCadenceCompositor::RuntimeRenderLayerModel& layer : layers)
|
||||||
@@ -66,6 +68,7 @@ bool RuntimeRenderScene::CommitRenderLayers(const std::vector<RenderCadenceCompo
|
|||||||
next.layerId = layer.id;
|
next.layerId = layer.id;
|
||||||
mLayers.push_back(std::move(next));
|
mLayers.push_back(std::move(next));
|
||||||
program = &mLayers.back();
|
program = &mLayers.back();
|
||||||
|
changedStructure = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasReadyPass = false;
|
bool hasReadyPass = false;
|
||||||
@@ -93,11 +96,16 @@ bool RuntimeRenderScene::CommitRenderLayers(const std::vector<RenderCadenceCompo
|
|||||||
program->shaderId = layer.shaderId;
|
program->shaderId = layer.shaderId;
|
||||||
program->pendingFingerprint = fingerprint;
|
program->pendingFingerprint = fingerprint;
|
||||||
layersToPrepare.push_back(layer);
|
layersToPrepare.push_back(layer);
|
||||||
|
changedStructure = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mLayerOrder != nextOrder)
|
||||||
|
changedStructure = true;
|
||||||
mLayerOrder = std::move(nextOrder);
|
mLayerOrder = std::move(nextOrder);
|
||||||
if (!layersToPrepare.empty())
|
if (!layersToPrepare.empty())
|
||||||
mPrepareWorker.Submit(layersToPrepare);
|
mPrepareWorker.Submit(layersToPrepare);
|
||||||
|
if (structuralChange)
|
||||||
|
*structuralChange = changedStructure;
|
||||||
error.clear();
|
error.clear();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ public:
|
|||||||
~RuntimeRenderScene();
|
~RuntimeRenderScene();
|
||||||
|
|
||||||
bool StartPrepareWorker(std::unique_ptr<HiddenGlWindow> sharedWindow, std::string& error);
|
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();
|
bool HasLayers();
|
||||||
void RenderFrame(uint64_t frameIndex, unsigned width, unsigned height, GLuint videoInputTexture = 0);
|
void RenderFrame(uint64_t frameIndex, unsigned width, unsigned height, GLuint videoInputTexture = 0);
|
||||||
void ShutdownGl();
|
void ShutdownGl();
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ bool RuntimeShaderRenderer::CommitPreparedProgram(RuntimePreparedShaderProgram&
|
|||||||
DestroyProgram();
|
DestroyProgram();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
mTextTextures.RefreshTextTextures();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,6 +71,7 @@ void RuntimeShaderRenderer::UpdateArtifactState(const RuntimeShaderArtifact& art
|
|||||||
mArtifact.parameterValues = artifact.parameterValues;
|
mArtifact.parameterValues = artifact.parameterValues;
|
||||||
mArtifact.message = artifact.message;
|
mArtifact.message = artifact.message;
|
||||||
mTextTextures.UpdateArtifactState(artifact);
|
mTextTextures.UpdateArtifactState(artifact);
|
||||||
|
mTextTextures.RefreshTextTextures();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RuntimeShaderRenderer::BuildPreparedProgram(
|
bool RuntimeShaderRenderer::BuildPreparedProgram(
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ bool RuntimeTextTextureCache::Configure(const RuntimeShaderArtifact& artifact, s
|
|||||||
TextTexture texture;
|
TextTexture texture;
|
||||||
texture.parameterId = definition.id;
|
texture.parameterId = definition.id;
|
||||||
texture.fontId = definition.fontId;
|
texture.fontId = definition.fontId;
|
||||||
|
texture.maxLength = definition.maxLength == 0 ? 64 : definition.maxLength;
|
||||||
mTextTextures.push_back(std::move(texture));
|
mTextTextures.push_back(std::move(texture));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,14 +102,21 @@ void RuntimeTextTextureCache::UpdateArtifactState(const RuntimeShaderArtifact& a
|
|||||||
mArtifact.parameterValues = artifact.parameterValues;
|
mArtifact.parameterValues = artifact.parameterValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RuntimeTextTextureCache::RefreshTextTextures()
|
||||||
|
{
|
||||||
|
for (TextTexture& textTexture : mTextTextures)
|
||||||
|
{
|
||||||
|
EnsureTextTexture(textTexture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void RuntimeTextTextureCache::BindTextTextures(GLuint program)
|
void RuntimeTextTextureCache::BindTextTextures(GLuint program)
|
||||||
{
|
{
|
||||||
for (std::size_t index = 0; index < mTextTextures.size(); ++index)
|
for (std::size_t index = 0; index < mTextTextures.size(); ++index)
|
||||||
{
|
{
|
||||||
TextTexture& textTexture = mTextTextures[index];
|
const TextTexture& textTexture = mTextTextures[index];
|
||||||
if (!EnsureTextTexture(textTexture))
|
if (textTexture.texture == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0 + kFirstTextTextureUnit + static_cast<GLuint>(index));
|
glActiveTexture(GL_TEXTURE0 + kFirstTextTextureUnit + static_cast<GLuint>(index));
|
||||||
glBindTexture(GL_TEXTURE_2D, textTexture.texture);
|
glBindTexture(GL_TEXTURE_2D, textTexture.texture);
|
||||||
}
|
}
|
||||||
@@ -318,21 +326,32 @@ bool RuntimeTextTextureCache::EnsureTextTexture(TextTexture& texture)
|
|||||||
|
|
||||||
unsigned width = 0;
|
unsigned width = 0;
|
||||||
unsigned height = 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)
|
if (pixels.empty() || width == 0 || height == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (texture.texture == 0)
|
if (texture.texture == 0)
|
||||||
glGenTextures(1, &texture.texture);
|
glGenTextures(1, &texture.texture);
|
||||||
|
|
||||||
|
GLint previousUnpackAlignment = 4;
|
||||||
|
glGetIntegerv(GL_UNPACK_ALIGNMENT, &previousUnpackAlignment);
|
||||||
glBindTexture(GL_TEXTURE_2D, texture.texture);
|
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);
|
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);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
glPixelStorei(GL_UNPACK_ALIGNMENT, previousUnpackAlignment);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
texture.cachedText = text;
|
texture.cachedText = text;
|
||||||
texture.width = width;
|
texture.width = width;
|
||||||
@@ -340,7 +359,7 @@ bool RuntimeTextTextureCache::EnsureTextTexture(TextTexture& texture)
|
|||||||
return texture.texture != 0;
|
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;
|
double advance = 0.0;
|
||||||
for (unsigned char character : text)
|
for (unsigned char character : text)
|
||||||
@@ -350,7 +369,8 @@ std::vector<unsigned char> RuntimeTextTextureCache::ComposeTextMask(const Atlas&
|
|||||||
advance += glyphIt->second.advance;
|
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;
|
height = kTextTextureHeight;
|
||||||
std::vector<unsigned char> mask(static_cast<std::size_t>(width) * height, 0);
|
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);
|
bool Configure(const RuntimeShaderArtifact& artifact, std::string& error);
|
||||||
void UpdateArtifactState(const RuntimeShaderArtifact& artifact);
|
void UpdateArtifactState(const RuntimeShaderArtifact& artifact);
|
||||||
|
void RefreshTextTextures();
|
||||||
void BindTextTextures(GLuint program);
|
void BindTextTextures(GLuint program);
|
||||||
void ShutdownGl();
|
void ShutdownGl();
|
||||||
|
|
||||||
@@ -57,13 +58,14 @@ private:
|
|||||||
GLuint texture = 0;
|
GLuint texture = 0;
|
||||||
unsigned width = 0;
|
unsigned width = 0;
|
||||||
unsigned height = 0;
|
unsigned height = 0;
|
||||||
|
unsigned maxLength = 64;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool LoadAtlas(const RenderCadenceCompositor::FontAtlasBuildOutput& output, Atlas& atlas, std::string& error) const;
|
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 LoadAtlasJson(const RenderCadenceCompositor::FontAtlasBuildOutput& output, Atlas& atlas, std::string& error) const;
|
||||||
bool LoadAtlasImage(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);
|
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;
|
const Atlas* FindAtlas(const std::string& fontId) const;
|
||||||
static const ShaderParameterValue* FindParameterValue(const RuntimeShaderArtifact& artifact, const std::string& parameterId);
|
static const ShaderParameterValue* FindParameterValue(const RuntimeShaderArtifact& artifact, const std::string& parameterId);
|
||||||
static std::string DefaultTextValue(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}` : ""}
|
placeholder={parameter.defaultValue ? `Default: ${parameter.defaultValue}` : ""}
|
||||||
value={draftValue ?? ""}
|
value={draftValue ?? ""}
|
||||||
onFocus={beginInteraction}
|
onFocus={beginInteraction}
|
||||||
onChange={(event) => sendValue(event.target.value)}
|
onChange={(event) => scheduleSendValue(event.target.value, false, 350)}
|
||||||
onBlur={endInteraction}
|
onBlur={endInteraction}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ export function useThrottledParameterValue(parameter, onParameterChange) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const scheduleSendValue = (value, immediate = false) => {
|
const scheduleSendValue = (value, immediate = false, throttleMs = 90) => {
|
||||||
setDraftValue(value);
|
setDraftValue(value);
|
||||||
latestDraftRef.current = value;
|
latestDraftRef.current = value;
|
||||||
isDirtyRef.current = true;
|
isDirtyRef.current = true;
|
||||||
@@ -93,7 +93,6 @@ export function useThrottledParameterValue(parameter, onParameterChange) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const throttleMs = 90;
|
|
||||||
const elapsed = now - lastSentAtRef.current;
|
const elapsed = now - lastSentAtRef.current;
|
||||||
|
|
||||||
if (immediate || elapsed >= throttleMs) {
|
if (immediate || elapsed >= throttleMs) {
|
||||||
|
|||||||
Reference in New Issue
Block a user