[WASAPI] fix stream types and frequencies enumeration
[xbmc.git] / xbmc / guilib / GUIFontTTFGLES.cpp
blob3a23a1d1f2496c04cdf8d032e661083a7f1d916e
1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "GUIFontTTFGLES.h"
11 #include "GUIFont.h"
12 #include "GUIFontManager.h"
13 #include "ServiceBroker.h"
14 #include "Texture.h"
15 #include "TextureManager.h"
16 #include "gui3d.h"
17 #include "rendering/MatrixGL.h"
18 #include "rendering/gles/RenderSystemGLES.h"
19 #include "settings/AdvancedSettings.h"
20 #include "settings/SettingsComponent.h"
21 #include "utils/GLUtils.h"
22 #include "utils/log.h"
23 #include "windowing/GraphicContext.h"
25 #include <cassert>
26 #include <memory>
28 // stuff for freetype
29 #include <ft2build.h>
30 #include FT_FREETYPE_H
31 #include FT_GLYPH_H
32 #include FT_OUTLINE_H
34 namespace
36 constexpr size_t ELEMENT_ARRAY_MAX_CHAR_INDEX = 1000;
37 } /* namespace */
39 CGUIFontTTF* CGUIFontTTF::CreateGUIFontTTF(const std::string& fontIdent)
41 return new CGUIFontTTFGLES(fontIdent);
44 CGUIFontTTFGLES::CGUIFontTTFGLES(const std::string& fontIdent) : CGUIFontTTF(fontIdent)
48 CGUIFontTTFGLES::~CGUIFontTTFGLES(void)
50 // It's important that all the CGUIFontCacheEntry objects are
51 // destructed before the CGUIFontTTFGLES goes out of scope, because
52 // our virtual methods won't be accessible after this point
53 m_dynamicCache.Flush();
54 DeleteHardwareTexture();
57 bool CGUIFontTTFGLES::FirstBegin()
59 CRenderSystemGLES* renderSystem =
60 dynamic_cast<CRenderSystemGLES*>(CServiceBroker::GetRenderSystem());
61 renderSystem->EnableGUIShader(ShaderMethodGLES::SM_FONTS);
62 GLenum pixformat = GL_ALPHA; // deprecated
63 GLenum internalFormat = GL_ALPHA;
65 if (renderSystem->ScissorsCanEffectClipping())
67 m_scissorClip = true;
69 else
71 m_scissorClip = false;
72 renderSystem->ResetScissors();
73 renderSystem->EnableGUIShader(ShaderMethodGLES::SM_FONTS_SHADER_CLIP);
76 if (m_textureStatus == TEXTURE_REALLOCATED)
78 if (glIsTexture(m_nTexture))
79 CServiceBroker::GetGUI()->GetTextureManager().ReleaseHwTexture(m_nTexture);
80 m_textureStatus = TEXTURE_VOID;
83 if (m_textureStatus == TEXTURE_VOID)
85 // Have OpenGL generate a texture object handle for us
86 glGenTextures(1, static_cast<GLuint*>(&m_nTexture));
88 // Bind the texture object
89 glBindTexture(GL_TEXTURE_2D, m_nTexture);
91 // Set the texture's stretching properties
92 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
93 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
95 // Set the texture image -- THIS WORKS, so the pixels must be wrong.
96 glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, m_texture->GetWidth(), m_texture->GetHeight(), 0,
97 pixformat, GL_UNSIGNED_BYTE, 0);
99 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
100 if (CServiceBroker::GetRenderSystem()->IsExtSupported("GL_EXT_texture_filter_anisotropic"))
102 int32_t aniso =
103 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_guiAnisotropicFiltering;
104 if (aniso > 1)
105 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);
107 #endif
109 VerifyGLState();
110 m_textureStatus = TEXTURE_UPDATED;
113 if (m_textureStatus == TEXTURE_UPDATED)
115 // Copies one more line in case we have to sample from there
116 m_updateY2 = std::min(m_updateY2 + 1, m_texture->GetHeight());
118 glBindTexture(GL_TEXTURE_2D, m_nTexture);
119 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, m_updateY1, m_texture->GetWidth(), m_updateY2 - m_updateY1,
120 pixformat, GL_UNSIGNED_BYTE,
121 m_texture->GetPixels() + m_updateY1 * m_texture->GetPitch());
123 m_updateY1 = m_updateY2 = 0;
124 m_textureStatus = TEXTURE_READY;
127 // Turn Blending On
128 glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_ONE);
129 glEnable(GL_BLEND);
130 glActiveTexture(GL_TEXTURE0);
131 glBindTexture(GL_TEXTURE_2D, m_nTexture);
133 return true;
136 void CGUIFontTTFGLES::LastEnd()
138 // static vertex arrays are not supported anymore
139 assert(m_vertex.empty());
141 CWinSystemBase* const winSystem = CServiceBroker::GetWinSystem();
142 if (!winSystem)
143 return;
145 CRenderSystemGLES* renderSystem =
146 dynamic_cast<CRenderSystemGLES*>(CServiceBroker::GetRenderSystem());
148 GLint posLoc = renderSystem->GUIShaderGetPos();
149 GLint colLoc = renderSystem->GUIShaderGetCol();
150 GLint tex0Loc = renderSystem->GUIShaderGetCoord0();
151 GLint clipUniformLoc = renderSystem->GUIShaderGetClip();
152 GLint coordStepUniformLoc = renderSystem->GUIShaderGetCoordStep();
153 GLint matrixUniformLoc = renderSystem->GUIShaderGetMatrix();
154 GLint depthLoc = renderSystem->GUIShaderGetDepth();
156 CreateStaticVertexBuffers();
158 // Enable the attributes used by this shader
159 glEnableVertexAttribArray(posLoc);
160 glEnableVertexAttribArray(colLoc);
161 glEnableVertexAttribArray(tex0Loc);
163 if (!m_vertexTrans.empty())
165 // Deal with the vertices that can be hardware clipped and therefore translated
167 // Bind our pre-calculated array to GL_ELEMENT_ARRAY_BUFFER
168 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementArrayHandle);
169 // Store current scissor
170 CGraphicContext& context = winSystem->GetGfxContext();
171 CRect scissor = context.StereoCorrection(context.GetScissors());
173 for (size_t i = 0; i < m_vertexTrans.size(); i++)
175 if (m_vertexTrans[i].m_vertexBuffer->bufferHandle == 0)
177 continue;
180 // Apply the clip rectangle
181 CRect clip = renderSystem->ClipRectToScissorRect(m_vertexTrans[i].m_clip);
182 if (!clip.IsEmpty())
184 // intersect with current scissor
185 clip.Intersect(scissor);
186 // skip empty clip
187 if (clip.IsEmpty())
188 continue;
190 if (m_scissorClip)
192 // clip using scissors
193 renderSystem->SetScissors(clip);
195 else
197 // clip using vertex shader
198 renderSystem->ResetScissors();
200 float x1 =
201 m_vertexTrans[i].m_clip.x1 - m_vertexTrans[i].m_translateX - m_vertexTrans[i].m_offsetX;
202 float y1 =
203 m_vertexTrans[i].m_clip.y1 - m_vertexTrans[i].m_translateY - m_vertexTrans[i].m_offsetY;
204 float x2 =
205 m_vertexTrans[i].m_clip.x2 - m_vertexTrans[i].m_translateX - m_vertexTrans[i].m_offsetX;
206 float y2 =
207 m_vertexTrans[i].m_clip.y2 - m_vertexTrans[i].m_translateY - m_vertexTrans[i].m_offsetY;
209 glUniform4f(clipUniformLoc, x1, y1, x2, y2);
211 // setup texture step
212 float stepX = context.GetGUIScaleX() / (static_cast<float>(m_textureWidth));
213 float stepY = context.GetGUIScaleY() / (static_cast<float>(m_textureHeight));
214 glUniform4f(coordStepUniformLoc, stepX, stepY, 1.0f, 1.0f);
217 // calculate the fractional offset to the ideal position
218 float fractX =
219 context.ScaleFinalXCoord(m_vertexTrans[i].m_translateX, m_vertexTrans[i].m_translateY);
220 float fractY =
221 context.ScaleFinalYCoord(m_vertexTrans[i].m_translateX, m_vertexTrans[i].m_translateY);
222 fractX = -fractX + std::round(fractX);
223 fractY = -fractY + std::round(fractY);
225 // proj * model * gui * scroll * translation * scaling * correction factor
226 CMatrixGL matrix = glMatrixProject.Get();
227 matrix.MultMatrixf(glMatrixModview.Get());
228 matrix.MultMatrixf(CMatrixGL(context.GetGUIMatrix()));
229 matrix.Translatef(m_vertexTrans[i].m_offsetX, m_vertexTrans[i].m_offsetY, 0.0f);
230 matrix.Translatef(m_vertexTrans[i].m_translateX, m_vertexTrans[i].m_translateY, 0.0f);
231 // the gui matrix messes with the scale. correct it here for now.
232 matrix.Scalef(context.GetGUIScaleX(), context.GetGUIScaleY(), 1.0f);
233 // the gui matrix doesn't align to exact pixel coords atm. correct it here for now.
234 matrix.Translatef(fractX, fractY, 0.0f);
236 // Apply the depth value of the layer
237 float depth = CServiceBroker::GetWinSystem()->GetGfxContext().GetTransformDepth();
238 glUniform1f(depthLoc, depth);
240 glUniformMatrix4fv(matrixUniformLoc, 1, GL_FALSE, matrix);
242 // Bind the buffer to the OpenGL context's GL_ARRAY_BUFFER binding point
243 glBindBuffer(GL_ARRAY_BUFFER, m_vertexTrans[i].m_vertexBuffer->bufferHandle);
245 // Do the actual drawing operation, split into groups of characters no
246 // larger than the pre-determined size of the element array
247 for (size_t character = 0; m_vertexTrans[i].m_vertexBuffer->size > character;
248 character += ELEMENT_ARRAY_MAX_CHAR_INDEX)
250 size_t count = m_vertexTrans[i].m_vertexBuffer->size - character;
251 count = std::min<size_t>(count, ELEMENT_ARRAY_MAX_CHAR_INDEX);
253 // Set up the offsets of the various vertex attributes within the buffer
254 // object bound to GL_ARRAY_BUFFER
255 glVertexAttribPointer(
256 posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex),
257 reinterpret_cast<GLvoid*>(character * sizeof(SVertex) * 4 + offsetof(SVertex, x)));
258 glVertexAttribPointer(
259 colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex),
260 reinterpret_cast<GLvoid*>(character * sizeof(SVertex) * 4 + offsetof(SVertex, r)));
261 glVertexAttribPointer(
262 tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex),
263 reinterpret_cast<GLvoid*>(character * sizeof(SVertex) * 4 + offsetof(SVertex, u)));
265 glDrawElements(GL_TRIANGLES, 6 * count, GL_UNSIGNED_SHORT, 0);
268 glMatrixModview.Pop();
270 // Restore the original scissor rectangle
271 if (m_scissorClip)
272 renderSystem->SetScissors(scissor);
273 // Unbind GL_ARRAY_BUFFER and GL_ELEMENT_ARRAY_BUFFER
274 glBindBuffer(GL_ARRAY_BUFFER, 0);
275 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
278 // Disable the attributes used by this shader
279 glDisableVertexAttribArray(posLoc);
280 glDisableVertexAttribArray(colLoc);
281 glDisableVertexAttribArray(tex0Loc);
283 renderSystem->DisableGUIShader();
286 CVertexBuffer CGUIFontTTFGLES::CreateVertexBuffer(const std::vector<SVertex>& vertices) const
288 assert(vertices.size() % 4 == 0);
289 GLuint bufferHandle = 0;
291 // Do not create empty buffers, leave buffer as 0, it will be ignored in drawing stage
292 if (!vertices.empty())
294 // Generate a unique buffer object name and put it in bufferHandle
295 glGenBuffers(1, &bufferHandle);
296 // Bind the buffer to the OpenGL context's GL_ARRAY_BUFFER binding point
297 glBindBuffer(GL_ARRAY_BUFFER, bufferHandle);
298 // Create a data store for the buffer object bound to the GL_ARRAY_BUFFER
299 // binding point (i.e. our buffer object) and initialise it from the
300 // specified client-side pointer
301 glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(SVertex), vertices.data(),
302 GL_STATIC_DRAW);
303 // Unbind GL_ARRAY_BUFFER
304 glBindBuffer(GL_ARRAY_BUFFER, 0);
307 return CVertexBuffer(bufferHandle, vertices.size() / 4, this);
310 void CGUIFontTTFGLES::DestroyVertexBuffer(CVertexBuffer& buffer) const
312 if (buffer.bufferHandle != 0)
314 // Release the buffer name for reuse
315 glDeleteBuffers(1, static_cast<GLuint*>(&buffer.bufferHandle));
316 buffer.bufferHandle = 0;
320 std::unique_ptr<CTexture> CGUIFontTTFGLES::ReallocTexture(unsigned int& newHeight)
322 newHeight = CTexture::PadPow2(newHeight);
324 std::unique_ptr<CTexture> newTexture =
325 CTexture::CreateTexture(m_textureWidth, newHeight, XB_FMT_A8);
327 if (!newTexture || !newTexture->GetPixels())
329 CLog::Log(LOGERROR, "GUIFontTTFGLES::{}: Error creating new cache texture for size {:f}",
330 __func__, m_height);
331 return nullptr;
334 m_textureHeight = newTexture->GetHeight();
335 m_textureScaleY = 1.0f / m_textureHeight;
336 m_textureWidth = newTexture->GetWidth();
337 m_textureScaleX = 1.0f / m_textureWidth;
338 if (m_textureHeight < newHeight)
339 CLog::Log(LOGWARNING,
340 "GUIFontTTFGLES::{}: allocated new texture with height of {}, requested {}", __func__,
341 m_textureHeight, newHeight);
342 m_staticCache.Flush();
343 m_dynamicCache.Flush();
345 memset(newTexture->GetPixels(), 0, m_textureHeight * newTexture->GetPitch());
346 if (m_texture)
348 m_updateY1 = 0;
349 m_updateY2 = m_texture->GetHeight();
351 unsigned char* src = m_texture->GetPixels();
352 unsigned char* dst = newTexture->GetPixels();
353 for (unsigned int y = 0; y < m_texture->GetHeight(); y++)
355 memcpy(dst, src, m_texture->GetPitch());
356 src += m_texture->GetPitch();
357 dst += newTexture->GetPitch();
361 m_textureStatus = TEXTURE_REALLOCATED;
363 return newTexture;
366 bool CGUIFontTTFGLES::CopyCharToTexture(
367 FT_BitmapGlyph bitGlyph, unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2)
369 FT_Bitmap bitmap = bitGlyph->bitmap;
371 unsigned char* source = bitmap.buffer;
372 unsigned char* target = m_texture->GetPixels() + y1 * m_texture->GetPitch() + x1;
374 for (unsigned int y = y1; y < y2; y++)
376 memcpy(target, source, x2 - x1);
377 source += bitmap.width;
378 target += m_texture->GetPitch();
381 switch (m_textureStatus)
383 case TEXTURE_UPDATED:
385 m_updateY1 = std::min(m_updateY1, y1);
386 m_updateY2 = std::max(m_updateY2, y2);
388 break;
390 case TEXTURE_READY:
392 m_updateY1 = y1;
393 m_updateY2 = y2;
394 m_textureStatus = TEXTURE_UPDATED;
396 break;
398 case TEXTURE_REALLOCATED:
400 m_updateY2 = std::max(m_updateY2, y2);
402 break;
404 case TEXTURE_VOID:
405 default:
406 break;
409 return true;
412 void CGUIFontTTFGLES::DeleteHardwareTexture()
414 if (m_textureStatus != TEXTURE_VOID)
416 if (glIsTexture(m_nTexture))
417 CServiceBroker::GetGUI()->GetTextureManager().ReleaseHwTexture(m_nTexture);
419 m_textureStatus = TEXTURE_VOID;
420 m_updateY1 = m_updateY2 = 0;
424 void CGUIFontTTFGLES::CreateStaticVertexBuffers(void)
426 if (m_staticVertexBufferCreated)
427 return;
429 // Bind a new buffer to the OpenGL context's GL_ELEMENT_ARRAY_BUFFER binding point
430 glGenBuffers(1, &m_elementArrayHandle);
431 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementArrayHandle);
433 // Create an array holding the mesh indices to convert quads to triangles
434 GLushort index[ELEMENT_ARRAY_MAX_CHAR_INDEX][6];
435 for (size_t i = 0; i < ELEMENT_ARRAY_MAX_CHAR_INDEX; i++)
437 index[i][0] = 4 * i;
438 index[i][1] = 4 * i + 1;
439 index[i][2] = 4 * i + 2;
440 index[i][3] = 4 * i + 1;
441 index[i][4] = 4 * i + 3;
442 index[i][5] = 4 * i + 2;
445 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof index, index, GL_STATIC_DRAW);
446 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
447 m_staticVertexBufferCreated = true;
450 void CGUIFontTTFGLES::DestroyStaticVertexBuffers(void)
452 if (!m_staticVertexBufferCreated)
453 return;
455 glDeleteBuffers(1, &m_elementArrayHandle);
456 m_staticVertexBufferCreated = false;
459 GLuint CGUIFontTTFGLES::m_elementArrayHandle{0};
460 bool CGUIFontTTFGLES::m_staticVertexBufferCreated{false};