Cocoa Port: Improve the handling of HUD font rendering for OpenGL display views running on old drivers.

This commit is contained in:
rogerman 2022-05-05 14:29:53 -07:00
parent 6e26980d87
commit 180df28ce7
5 changed files with 95 additions and 37 deletions

View File

@ -90,6 +90,7 @@ void ClientDisplayPresenter::__InstanceInit(const ClientDisplayPresenterProperti
_scaleFactor = 1.0; _scaleFactor = 1.0;
_hudObjectScale = 1.0; _hudObjectScale = 1.0;
_isHUDRenderMipmapped = false;
_isHUDVisible = false; _isHUDVisible = false;
_showExecutionSpeed = false; _showExecutionSpeed = false;
_showVideoFPS = true; _showVideoFPS = true;
@ -566,6 +567,17 @@ void ClientDisplayPresenter::SetHUDObjectScale(float objectScale)
this->_hudObjectScale = objectScale; this->_hudObjectScale = objectScale;
} }
bool ClientDisplayPresenter::WillHUDRenderMipmapped() const
{
return this->_isHUDRenderMipmapped;
}
void ClientDisplayPresenter::SetHUDRenderMipmapped(const bool mipmapState)
{
this->_isHUDRenderMipmapped = mipmapState;
}
bool ClientDisplayPresenter::GetHUDVisibility() const bool ClientDisplayPresenter::GetHUDVisibility() const
{ {
return this->_isHUDVisible; return this->_isHUDVisible;

View File

@ -154,6 +154,7 @@ protected:
double _scaleFactor; double _scaleFactor;
double _hudObjectScale; double _hudObjectScale;
bool _isHUDRenderMipmapped;
bool _isHUDVisible; bool _isHUDVisible;
bool _showExecutionSpeed; bool _showExecutionSpeed;
bool _showVideoFPS; bool _showVideoFPS;
@ -260,6 +261,8 @@ public:
float GetHUDObjectScale() const; float GetHUDObjectScale() const;
virtual void SetHUDObjectScale(float objectScale); virtual void SetHUDObjectScale(float objectScale);
bool WillHUDRenderMipmapped() const;
void SetHUDRenderMipmapped(const bool mipmapState);
bool GetHUDVisibility() const; bool GetHUDVisibility() const;
virtual void SetHUDVisibility(const bool visibleState); virtual void SetHUDVisibility(const bool visibleState);
bool GetHUDShowExecutionSpeed() const; bool GetHUDShowExecutionSpeed() const;

View File

@ -37,7 +37,7 @@ static const char *HUDOutputVertShader_100 = {"\
uniform bool renderFlipped; \n\ uniform bool renderFlipped; \n\
\n\ \n\
VARYING vec4 vtxColor; \n\ VARYING vec4 vtxColor; \n\
VARYING vec2 texCoord[1]; \n\ VARYING vec2 texCoord; \n\
\n\ \n\
void main() \n\ void main() \n\
{ \n\ { \n\
@ -53,7 +53,7 @@ static const char *HUDOutputVertShader_100 = {"\
vec2( 0.0, scalar)); \n\ vec2( 0.0, scalar)); \n\
\n\ \n\
vtxColor = inColor; \n\ vtxColor = inColor; \n\
texCoord[0] = inTexCoord0; \n\ texCoord = inTexCoord0; \n\
gl_Position = vec4(projection * rotation * scale * inPosition, 0.0, 1.0);\n\ gl_Position = vec4(projection * rotation * scale * inPosition, 0.0, 1.0);\n\
\n\ \n\
if (renderFlipped)\n\ if (renderFlipped)\n\
@ -66,12 +66,12 @@ static const char *HUDOutputVertShader_100 = {"\
// FRAGMENT SHADER FOR HUD OUTPUT // FRAGMENT SHADER FOR HUD OUTPUT
static const char *HUDOutputFragShader_110 = {"\ static const char *HUDOutputFragShader_110 = {"\
VARYING vec4 vtxColor;\n\ VARYING vec4 vtxColor;\n\
VARYING vec2 texCoord[1];\n\ VARYING vec2 texCoord;\n\
uniform sampler2D tex;\n\ uniform sampler2D tex;\n\
\n\ \n\
void main()\n\ void main()\n\
{\n\ {\n\
OUT_FRAG_COLOR = SAMPLE4_TEX_2D(tex, texCoord[0]) * vtxColor;\n\ OUT_FRAG_COLOR = SAMPLE4_TEX_2D(tex, texCoord) * vtxColor;\n\
}\n\ }\n\
"}; "};
@ -5076,25 +5076,7 @@ void OGLVideoOutput::Init()
(*this->_layerList)[i]->SetVisibility(wasPreviouslyVisibleList[i]); (*this->_layerList)[i]->SetVisibility(wasPreviouslyVisibleList[i]);
} }
// Render State Setup (common to both shaders and fixed-function pipeline) this->PrerenderStateSetupOGL();
glEnable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glDisable(GL_DITHER);
glDisable(GL_STENCIL_TEST);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
// Set up fixed-function pipeline render states.
if (!this->_contextInfo->IsShaderSupported())
{
glDisable(GL_ALPHA_TEST);
glDisable(GL_LIGHTING);
glDisable(GL_FOG);
glEnable(GL_TEXTURE_RECTANGLE_ARB);
}
// Set up clear attributes
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// Set up textures // Set up textures
glTextureRangeAPPLE(GL_TEXTURE_RECTANGLE_ARB, this->_vfMasterDstBufferSize, this->_vfMasterDstBuffer); glTextureRangeAPPLE(GL_TEXTURE_RECTANGLE_ARB, this->_vfMasterDstBufferSize, this->_vfMasterDstBuffer);
@ -5218,6 +5200,36 @@ void OGLVideoOutput::CopyFrameToBuffer(uint32_t *dstBuffer)
this->_needUpdateViewport = true; this->_needUpdateViewport = true;
} }
void OGLVideoOutput::PrerenderStateSetupOGL()
{
// If the context is managed by us, then setting all of OpenGL's states
// once at initialization time should be enough.
//
// But if the context is managed by a third party, then this method can
// be manually called before rendering the video output if necessary.
//
// The most notable state here is enabling blending, which HUD rendering
// requires.
// Render State Setup (common to both shaders and fixed-function pipeline)
glEnable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glDisable(GL_DITHER);
glDisable(GL_STENCIL_TEST);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// Set up fixed-function pipeline render states.
if (!this->_contextInfo->IsShaderSupported())
{
glDisable(GL_ALPHA_TEST);
glDisable(GL_LIGHTING);
glDisable(GL_FOG);
glEnable(GL_TEXTURE_2D);
glEnable(GL_TEXTURE_RECTANGLE_ARB);
}
}
void OGLVideoOutput::RenderFrameOGL(bool isRenderingFlipped) void OGLVideoOutput::RenderFrameOGL(bool isRenderingFlipped)
{ {
if (this->_needUpdateViewport) if (this->_needUpdateViewport)
@ -6274,6 +6286,9 @@ OGLHUDLayer::OGLHUDLayer(OGLVideoOutput *oglVO)
_uniformScalar = glGetUniformLocation(_program->GetProgramID(), "scalar"); _uniformScalar = glGetUniformLocation(_program->GetProgramID(), "scalar");
_uniformViewSize = glGetUniformLocation(_program->GetProgramID(), "viewSize"); _uniformViewSize = glGetUniformLocation(_program->GetProgramID(), "viewSize");
_uniformRenderFlipped = glGetUniformLocation(_program->GetProgramID(), "renderFlipped"); _uniformRenderFlipped = glGetUniformLocation(_program->GetProgramID(), "renderFlipped");
GLint uniformTexSampler = glGetUniformLocation(_program->GetProgramID(), "tex");
glUniform1i(uniformTexSampler, 0);
glUseProgram(0); glUseProgram(0);
} }
else else
@ -6370,26 +6385,35 @@ OGLHUDLayer::~OGLHUDLayer()
void OGLHUDLayer::CopyHUDFont(const FT_Face &fontFace, const size_t glyphSize, const size_t glyphTileSize, GlyphInfo *glyphInfo) void OGLHUDLayer::CopyHUDFont(const FT_Face &fontFace, const size_t glyphSize, const size_t glyphTileSize, GlyphInfo *glyphInfo)
{ {
FT_Error error = FT_Err_Ok; FT_Error error = FT_Err_Ok;
std::vector<uint32_t *> workingBufferList;
workingBufferList.reserve(16);
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, this->_texCharMap); glBindTexture(GL_TEXTURE_2D, this->_texCharMap);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
GLint texLevel = 0; GLint texLevel = 0;
for (size_t tileSize = glyphTileSize, gSize = glyphSize; tileSize >= 4; texLevel++, tileSize >>= 1, gSize = (GLfloat)tileSize * 0.75f) for (size_t tileSize = glyphTileSize, texSize = glyphTileSize * 16, gSize = glyphSize; texSize >= 1; texLevel++, tileSize >>= 1, texSize >>= 1, gSize = (GLfloat)tileSize * 0.75f)
{ {
const size_t charMapBufferPixCount = (16 * tileSize) * (16 * tileSize); const size_t charMapBufferPixCount = texSize * texSize;
const uint32_t fontColor = 0x00FFFFFF; const uint32_t fontColor = 0x00FFFFFF;
// Allocate a working buffer for FreeType to draw in. We then need to add
// it to a list so that we can deallocate the working buffer after OpenGL
// has copied the buffer to its associated texture.
uint32_t *charMapBuffer = (uint32_t *)malloc(charMapBufferPixCount * 2 * sizeof(uint32_t)); uint32_t *charMapBuffer = (uint32_t *)malloc(charMapBufferPixCount * 2 * sizeof(uint32_t));
workingBufferList.push_back(charMapBuffer);
for (size_t i = 0; i < charMapBufferPixCount; i++) for (size_t i = 0; i < charMapBufferPixCount; i++)
{ {
charMapBuffer[i] = fontColor; charMapBuffer[i] = fontColor;
} }
if (tileSize == 0)
{
continue;
}
error = FT_Set_Char_Size(fontFace, gSize << 6, gSize << 6, 72, 72); error = FT_Set_Char_Size(fontFace, gSize << 6, gSize << 6, 72, 72);
if (error) if (error)
{ {
@ -6404,7 +6428,7 @@ void OGLHUDLayer::CopyHUDFont(const FT_Face &fontFace, const size_t glyphSize, c
for (size_t pixIndex = 0; pixIndex < tileSize; pixIndex++) for (size_t pixIndex = 0; pixIndex < tileSize; pixIndex++)
{ {
const uint32_t colorRGBA8888 = 0xFFFFFFFF; const uint32_t colorRGBA8888 = 0xFFFFFFFF;
charMapBuffer[(tileSize + pixIndex) + (rowIndex * (16 * tileSize))] = colorRGBA8888; charMapBuffer[(tileSize + pixIndex) + (rowIndex * texSize)] = colorRGBA8888;
} }
} }
@ -6420,7 +6444,6 @@ void OGLHUDLayer::CopyHUDFont(const FT_Face &fontFace, const size_t glyphSize, c
const uint16_t tileOffsetX = (c & 0x0F) * tileSize; const uint16_t tileOffsetX = (c & 0x0F) * tileSize;
const uint16_t tileOffsetY = (c >> 4) * tileSize; const uint16_t tileOffsetY = (c >> 4) * tileSize;
const uint16_t tileOffsetY_texture = tileOffsetY - (tileSize - gSize + (gSize / 16)); const uint16_t tileOffsetY_texture = tileOffsetY - (tileSize - gSize + (gSize / 16));
const uint16_t texSize = tileSize * 16;
const GLuint glyphWidth = glyphSlot->bitmap.width; const GLuint glyphWidth = glyphSlot->bitmap.width;
if (tileSize == glyphTileSize) if (tileSize == glyphTileSize)
@ -6444,12 +6467,19 @@ void OGLHUDLayer::CopyHUDFont(const FT_Face &fontFace, const size_t glyphSize, c
} }
} }
glTexImage2D(GL_TEXTURE_2D, texLevel, GL_RGBA, 16 * tileSize, 16 * tileSize, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, charMapBuffer); glTexImage2D(GL_TEXTURE_2D, texLevel, GL_RGBA, texSize, texSize, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, charMapBuffer);
} }
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, texLevel - 1); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, texLevel - 1);
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
// Synchronize here, then free all previously allocated working buffers.
glFinish();
for (size_t i = 0; i < workingBufferList.size(); i++)
{
free(workingBufferList[i]);
}
} }
void OGLHUDLayer::_UpdateVerticesOGL() void OGLHUDLayer::_UpdateVerticesOGL()
@ -6551,19 +6581,19 @@ void OGLHUDLayer::RenderOGL(bool isRenderingFlipped)
// First, draw the inputs. // First, draw the inputs.
if (this->_output->GetHUDShowInput()) if (this->_output->GetHUDShowInput())
{ {
const ClientDisplayPresenterProperties &cdv = this->_output->GetPresenterProperties(); const ClientDisplayPresenterProperties &cdp = this->_output->GetPresenterProperties();
if (this->_output->GetContextInfo()->IsShaderSupported()) if (this->_output->GetContextInfo()->IsShaderSupported())
{ {
glUniform1f(this->_uniformAngleDegrees, cdv.rotation); glUniform1f(this->_uniformAngleDegrees, cdp.rotation);
glUniform1f(this->_uniformScalar, cdv.viewScale); glUniform1f(this->_uniformScalar, cdp.viewScale);
} }
else else
{ {
glMatrixMode(GL_MODELVIEW); glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); glLoadIdentity();
glRotatef(cdv.rotation, 0.0f, 0.0f, 1.0f); glRotatef(cdp.rotation, 0.0f, 0.0f, 1.0f);
glScalef(cdv.viewScale, cdv.viewScale, 1.0f); glScalef(cdp.viewScale, cdp.viewScale, 1.0f);
} }
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@ -6615,8 +6645,16 @@ void OGLHUDLayer::RenderOGL(bool isRenderingFlipped)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, 0.00f); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, 0.00f);
} }
else else
{
if (this->_output->WillHUDRenderMipmapped())
{ {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
}
else
{
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_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -0.50f); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -0.50f);
} }
@ -6696,6 +6734,9 @@ OGLDisplayLayer::OGLDisplayLayer(OGLVideoOutput *oglVO)
_uniformViewSize = glGetUniformLocation(finalOutputProgramID, "viewSize"); _uniformViewSize = glGetUniformLocation(finalOutputProgramID, "viewSize");
_uniformRenderFlipped = glGetUniformLocation(finalOutputProgramID, "renderFlipped"); _uniformRenderFlipped = glGetUniformLocation(finalOutputProgramID, "renderFlipped");
_uniformBacklightIntensity = glGetUniformLocation(finalOutputProgramID, "backlightIntensity"); _uniformBacklightIntensity = glGetUniformLocation(finalOutputProgramID, "backlightIntensity");
GLint uniformTexSampler = glGetUniformLocation(finalOutputProgramID, "tex");
glUniform1i(uniformTexSampler, 0);
glUseProgram(0); glUseProgram(0);
} }
else else

View File

@ -455,6 +455,7 @@ public:
// Client view interface // Client view interface
virtual void ProcessDisplays(); virtual void ProcessDisplays();
virtual void CopyFrameToBuffer(uint32_t *dstBuffer); virtual void CopyFrameToBuffer(uint32_t *dstBuffer);
virtual void PrerenderStateSetupOGL();
virtual void RenderFrameOGL(bool isRenderingFlipped); virtual void RenderFrameOGL(bool isRenderingFlipped);
virtual const OGLProcessedFrameInfo& GetProcessedFrameInfo(); virtual const OGLProcessedFrameInfo& GetProcessedFrameInfo();

View File

@ -1296,6 +1296,7 @@ static std::unordered_map<NSScreen *, DisplayWindowController *> _screenMap; //
NSString *fontPath = [[NSBundle mainBundle] pathForResource:@"SourceSansPro-Bold" ofType:@"otf"]; NSString *fontPath = [[NSBundle mainBundle] pathForResource:@"SourceSansPro-Bold" ofType:@"otf"];
cdv->Get3DPresenter()->SetHUDFontPath([fontPath cStringUsingEncoding:NSUTF8StringEncoding]); cdv->Get3DPresenter()->SetHUDFontPath([fontPath cStringUsingEncoding:NSUTF8StringEncoding]);
cdv->Get3DPresenter()->SetHUDRenderMipmapped(true);
if (scaleFactor != 1.0f) if (scaleFactor != 1.0f)
{ {