vdr-plugin-softhddevice-drm-gles 1.6.4-d0291bb
openglosd.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: AGPL-3.0-or-later
2
18#include <algorithm>
19#include <cinttypes>
20#include <cstdio>
21#include <cstdlib>
22#include <vector>
23
24#ifdef GRIDPOINTS
25#include <string>
26#endif
27
28#include <sys/ioctl.h>
29
30#include <GLES2/gl2.h>
31#include <glm/glm.hpp>
32#include <glm/gtc/matrix_transform.hpp>
33#include <glm/gtc/type_ptr.hpp>
34
35#include <vdr/osd.h>
36
37#include "logger.h"
38#include "misc.h"
39#include "openglosd.h"
40#include "openglshader.h"
41#include "softhddevice.h"
42#include "videorender.h"
43
44// This maybe useful for skin developing and marks the rects of the single draws
45#ifdef GRIDPOINTS
46#define GRIDPOINTSTEXT 1
47#define GRIDRECT 1
48#define GRIDTEXT 0
49#define GRIDPOINTSIZE 3
50#define GRIDPOINTOFFSET 4
51#define GRIDPOINTSTXTSIZE 14
52#define GRIDPOINTBG clrTransparent
53#define GRIDPOINTCLR 0xFFFF0000
54#endif
55
63static void ConvertColor(const GLint &colARGB, glm::vec4 &col) {
64 col.a = ((colARGB & 0xFF000000) >> 24) / 255.0;
65 col.r = ((colARGB & 0x00FF0000) >> 16) / 255.0;
66 col.g = ((colARGB & 0x0000FF00) >> 8 ) / 255.0;
67 col.b = ((colARGB & 0x000000FF) ) / 255.0;
68}
69
76
83
84/****************************************************************************************
85 * cOglShader
86 ***************************************************************************************/
88{
90}
91
93{
94 const char *vertexCode = NULL;
95 const char *fragmentCode = NULL;
96
97 m_type = type;
98 switch (m_type) {
99 case stRect:
102 break;
103 case stTexture:
106 break;
107 case stTextureSwapBR:
110 break;
111 case stText:
114 break;
115 default:
116 LOGERROR("openglosd: %s: unknown shader type", __FUNCTION__);
117 break;
118 }
119
120 if (vertexCode == NULL || fragmentCode == NULL) {
121 LOGERROR("openglosd: %s: error reading shader", __FUNCTION__);
122 return false;
123 }
124
126 LOGERROR("openglosd: %s: error compiling shader", __FUNCTION__);
127 return false;
128 }
129
130 return true;
131}
132
137
142
144{
146}
147
149{
151}
152
154{
156}
157
158void cOglShader::SetMatrix4(const GLchar *name, const glm::mat4 &matrix)
159{
161}
162
163bool cOglShader::Compile(const char *vertexCode, const char *fragmentCode)
164{
166
167 // vertex shader
172 return false;
173
174 // fragment shader
179 return false;
180
181 // link program
185 GL_CHECK(glBindAttribLocation(m_id, 0, "position"));
186 GL_CHECK(glBindAttribLocation(m_id, 1, "texCoords"));
188 if (!CheckCompileErrors(m_id, true))
189 return false;
190
191 // delete the shaders as they're linked into our program now and no longer necessary
194 return true;
195}
196
199 GLchar infoLog[1024];
200 if (!program) {
202 if (!success) {
203 GL_CHECK(glGetShaderInfoLog(object, 1024, NULL, infoLog));
204 LOGERROR("openglosd: %s: Compile-time error: Type: %d - %s", __FUNCTION__, m_type, infoLog);
205 return false;
206 }
207 } else {
209 if (!success) {
210 GL_CHECK(glGetProgramInfoLog(object, 1024, NULL, infoLog));
211 LOGERROR("openglosd: %s: Link-time error: Type: %d - %s", __FUNCTION__, m_type, infoLog);
212 return false;
213 }
214 }
215 return true;
216}
217
218#define KERNING_UNKNOWN (-10000)
219/****************************************************************************************
220 * cOglGlyph
221 ***************************************************************************************/
223 : m_charCode(charCode),
224 m_bearingLeft(ftGlyph->left),
225 m_bearingTop(ftGlyph->top),
226 m_width(ftGlyph->bitmap.width),
227 m_height(ftGlyph->bitmap.rows),
228 m_pBuffer(ftGlyph->bitmap.buffer),
229 m_advanceX(ftGlyph->root.advance.x >> 16) // value in 1/2^16 pixel
230{
231}
232
238
240{
241 for (int i = m_pKerningCache.Size(); --i > 0; ) {
242 if (m_pKerningCache[i].prevSym == prevSym)
243 return m_pKerningCache[i].kerning;
244 }
245 return KERNING_UNKNOWN;
246}
247
248void cOglGlyph::SetKerningCache(FT_ULong prevSym, int kerning)
249{
250 m_pKerningCache.Append(tKerning(prevSym, kerning));
251}
252
257
285
286/****************************************************************************************
287 * cOglFontAtlas
288 ***************************************************************************************/
290{
291 int maxAtlasWidth;
293
294 FT_Set_Pixel_Sizes(face, 0, height);
295 FT_GlyphSlot g = face->glyph;
296
297 int rowW = 0;
298 int rowH = 0;
299
300 // Find the minimum size for the texture holding all visible ASCII characters
301 for (int i = MIN_CHARCODE; i <= MAX_CHARCODE; i++) {
303 LOGDEBUG2(L_OPENGL, "openglosd: %s: Loading char %d failed!", __FUNCTION__, i);
304 continue;
305 }
306
307 // do some glyph manipulation
310 if (FT_Stroker_New(g->library, &stroker)) {
311 LOGERROR("openglosd: %s: FT_Stroker_New error!", __FUNCTION__);
312 return;
313 }
314
315 float outlineWidth = 0.25f;
318
319 if (FT_Get_Glyph(g, &ftGlyph)) {
320 LOGERROR("openglosd: %s: FT_Get_Glyph error!", __FUNCTION__);
321 return;
322 }
323
325 LOGERROR("openglosd: %s: FT_Glyph_StrokeBoder error!", __FUNCTION__);
326 return;
327 }
328
330
332 LOGERROR("openglosd: %s: FT_Glyph_To_Bitmap error!", __FUNCTION__);
333 return;
334 }
335
337
338 if (rowW + bGlyph->bitmap.width + 1 >= (unsigned int)maxAtlasWidth) {
339 m_width = std::max(m_width, rowW);
340 m_height += rowH;
341 rowW = 0;
342 rowH = 0;
343 }
344 rowW += bGlyph->bitmap.width + 1;
345 rowH = std::max(rowH, (int)bGlyph->bitmap.rows);
346
348 }
349
350 m_width = std::max(m_width, rowW);
351 m_height += rowH;
352
353 // Create a texture that will be used to hold all ASCII glyphs
356 LOGDEBUG2(L_OPENGL, "openglosd: %s: Try creating font atlas texture with w %d h %d (max %d)", __FUNCTION__, m_width, m_height, maxAtlasWidth);
357
360 0,
362 m_width,
363 m_height,
364 0,
367 0
368 ));
369
375
376 int offsetX = 0;
377 int offsetY = 0;
378
379 rowH = 0;
380
381 // Now do the real upload
382 for (FT_ULong i = MIN_CHARCODE; i <= MAX_CHARCODE; i++) {
384 LOGWARNING("openglosd: %s: Loading char %c failed!", __FUNCTION__, i);
385 continue;
386 }
387
388 // do some glyph manipulation
391 if (FT_Stroker_New(g->library, &stroker)) {
392 LOGERROR("openglosd: %s: FT_Stroker_New error!", __FUNCTION__);
393 return;
394 }
395
396 float outlineWidth = 0.25f;
399
400 if (FT_Get_Glyph(g, &ftGlyph)) {
401 LOGERROR("openglosd: %s: FT_Get_Glyph error!", __FUNCTION__);
402 return;
403 }
404
406 LOGERROR("openglosd: %s: FT_Glyph_StrokeBoder error!", __FUNCTION__);
407 return;
408 }
409
411
413 LOGERROR("openglosd: %s: FT_Glyph_To_Bitmap error!", __FUNCTION__);
414 return;
415 }
417
418 // pushing the glyphs to the texture
419 if (offsetX + bGlyph->bitmap.width + 1 >= (unsigned int)maxAtlasWidth) {
420 offsetY += rowH;
421 rowH = 0;
422 offsetX = 0;
423 }
424
427 0,
428 offsetX,
429 offsetY,
430 bGlyph->bitmap.width,
431 bGlyph->bitmap.rows,
434 bGlyph->bitmap.buffer
435 ));
436
438 rowH = std::max(rowH, (int)bGlyph->bitmap.rows);
439 offsetX += bGlyph->bitmap.width + 1;
440
442 }
443
445 LOGDEBUG2(L_OPENGL, "openglosd: %s: Created a %d x %d (%d kB) FontAtlas for fontsize %d, rowH %d, rowW %d",
446 __FUNCTION__, m_width, m_height, m_width * m_height / 1024, height, rowH, rowW);
447}
448
450 if (m_texture)
452
453 for (FT_ULong i = MIN_CHARCODE; i <= MAX_CHARCODE; i++) {
454 if (m_pGlyph[i - MIN_CHARCODE]) {
455 delete m_pGlyph[i - MIN_CHARCODE];
456 m_pGlyph[i - MIN_CHARCODE] = nullptr;
457 }
458 }
459}
460
463 return nullptr;
464
465 return m_pGlyph[sym - MIN_CHARCODE];
466}
467
471
472/****************************************************************************************
473 * cOglFont
474 ***************************************************************************************/
477bool cOglFont::s_initiated = false;
478
480 : m_name(fontName),
481 m_size(charHeight)
482{
484 if (error)
485 LOGERROR("openglosd: %s: failed to open %s!", __FUNCTION__, *m_name);
486
489 int count = 0;
490 int minIndex = 0;
491 int maxIndex = 0;
492
496 while (gindex != 0) {
497 count++;
499 minIndex = std::min(minIndex, (int)gindex);
500 maxIndex = std::max(maxIndex, (int)gindex);
501 }
502
503 FT_Set_Char_Size(m_face, 0, m_size * 64, 0, 0);
504 m_height = (m_face->size->metrics.ascender - m_face->size->metrics.descender + 63) / 64;
505 m_bottom = abs((m_face->size->metrics.descender - 63) / 64);
507 LOGDEBUG2(L_OPENGL, "openglosd: %s: Created new font: %s (%d) height: %d, bottom: %d - %d chars (%d - %d)", __FUNCTION__, fontName, m_size, m_height, m_bottom, count, minIndex, maxIndex);
508}
509
511{
512 delete m_pAtlas;
514}
515
516cOglFont *cOglFont::Get(const char *name, int charHeight)
517{
518 if (!s_pFonts)
519 Init();
520
521 cOglFont *font;
522 for (font = s_pFonts->First(); font; font = s_pFonts->Next(font))
523 if (!strcmp(font->Name(), name) && charHeight == font->Size()) {
524 return font;
525 }
526 font = new cOglFont(name, charHeight);
527 s_pFonts->Add(font);
528
529 return font;
530}
531
533{
535 LOGERROR("openglosd: %s: failed to initialize FreeType library!", __FUNCTION__);
536 return;
537 }
539 s_initiated = true;
540}
541
543{
544 if (!s_initiated)
545 return;
546 delete s_pFonts;
547 s_pFonts = 0;
549 LOGERROR("openglosd: %s: failed to deinitialize FreeType library!", __FUNCTION__);
550
551 s_ftLib = 0;
552}
553
555{
556 // Non-breaking space:
557 if (charCode == 0xA0)
558 charCode = 0x20;
559
560 // Lookup in cache:
561 for (cOglGlyph *g = m_glyphCache.First(); g; g = m_glyphCache.Next(g)) {
562 if (g->CharCode() == charCode) {
563 return g;
564 }
565 }
566
568
570 // Load glyph image into the slot (erase previous one):
572 if (error) {
573 LOGERROR("openglosd: %s: FT_Error (0x%02x) : %s", __FUNCTION__, FT_Errors[error].code, FT_Errors[error].message);
574 return NULL;
575 }
576
580 if (error) {
581 LOGERROR("openglosd: %s: FT_Stroker_New FT_Error (0x%02x) : %s", __FUNCTION__, FT_Errors[error].code, FT_Errors[error].message);
582 return NULL;
583 }
584 float outlineWidth = 0.25f;
586
587 error = FT_Get_Glyph(m_face->glyph, &ftGlyph);
588 if (error) {
589 LOGERROR("openglosd: %s: FT_Get_Glyph FT_Error (0x%02x) : %s", __FUNCTION__, FT_Errors[error].code, FT_Errors[error].message);
590 return NULL;
591 }
592
594 if (error) {
595 LOGERROR("openglosd: %s: FT_Glyph_StrokeBorder FT_Error (0x%02x) : %s", __FUNCTION__, FT_Errors[error].code, FT_Errors[error].message);
596 return NULL;
597 }
599
601 if (error) {
602 LOGERROR("openglosd: %s: FT_Glyph_To_Bitmap FT_Error (0x%02x) : %s", __FUNCTION__, FT_Errors[error].code, FT_Errors[error].message);
603 return NULL;
604 }
605
607 glyph->LoadTexture();
608 m_glyphCache.Add(glyph);
610
611 return glyph;
612}
613
615{
616 int kerning = 0;
617 if (glyph && prevSym) {
618 kerning = glyph->GetKerningCache(prevSym);
619 if (kerning == KERNING_UNKNOWN) {
624 kerning = delta.x / 64;
625 glyph->SetKerningCache(prevSym, kerning);
626 }
627 }
628
629 return kerning;
630}
631
632/****************************************************************************************
633 * cOglFb
634 ***************************************************************************************/
636 : m_width(width),
637 m_height(height),
638 m_viewPortWidth(viewPortWidth),
639 m_viewPortHeight(viewPortHeight)
640{
642 m_scrollable = true;
643}
644
652
677
685
691
693{
694 if (!m_initiated)
695 return false;
697 return true;
698}
699
700/****************************************************************************************
701 * cOglOutputFb
702 ***************************************************************************************/
727
734
735/****************************************************************************************
736 * cOglVb
737 ***************************************************************************************/
738
739bool cOglVb::Init(void)
740{
741 switch (m_type) {
742 case vbTexture: // Texture VBO definition
743 m_sizeVertex1 = 2;
744 m_sizeVertex2 = 2;
745 m_numVertices = 6;
748 break;
749 case vbTextureSwapBR: // Texture VBO definition, BR swapped
750 m_sizeVertex1 = 2;
751 m_sizeVertex2 = 2;
752 m_numVertices = 6;
755 break;
756 case vbRect: // Rectangle VBO definition
757 m_sizeVertex1 = 2;
758 m_sizeVertex2 = 0;
759 m_numVertices = 4;
762 break;
763 case vbEllipse: // Ellipse VBO definition
764 m_sizeVertex1 = 2;
765 m_sizeVertex2 = 0;
766 m_numVertices = 182;
769 break;
770 case vbSlope: // Slope VBO definition
771 m_sizeVertex1 = 2;
772 m_sizeVertex2 = 0;
773 m_numVertices = 102;
776 break;
777 case vbText: // Text VBO definition
778 m_sizeVertex1 = 2;
779 m_sizeVertex2 = 2;
780 m_numVertices = 6;
783 break;
784 default:
785 break;
786 }
787
790
792
795 if (m_sizeVertex2 > 0) {
798 }
799
801
802 return true;
803}
804
815
820
822{
823 Shaders[m_shader]->Use();
824}
825
831
836
838{
839 glm::vec4 col;
841 Shaders[m_shader]->SetVector4f("inColor", col.r, col.g, col.b, col.a);
842}
843
845{
846 glm::vec4 col;
848 Shaders[m_shader]->SetVector4f("bColor", col.r, col.g, col.b, col.a);
849}
850
852{
853 Shaders[m_shader]->SetInteger("screenTexture", value);
854}
855
857{
858 Shaders[m_shader]->SetVector4f("alpha", 1.0f, 1.0f, 1.0f, (GLfloat)(alpha) / 255.0f);
859}
860
862{
863 glm::mat4 projection = glm::ortho(0.0f, (GLfloat)width, (GLfloat)height, 0.0f, -1.0f, 1.0f);
864 Shaders[m_shader]->SetMatrix4("projection", projection);
865}
866
875
884
886{
887 if (count == 0)
890}
891
892/****************************************************************************************
893 * cOpenGLCmd
894 ***************************************************************************************/
895
896//------------------ cOglCmdInitOutputFb --------------------
898{
899 bool ok = m_pOutputFramebuffer->Init();
901 return ok;
902}
903
904//------------------ cOglCmdInitFb --------------------------
906{
907 bool ok = m_pFramebuffer->Init();
909 if (m_wait)
910 m_wait->Signal();
911 return ok;
912}
913
914//------------------ cOglCmdDeleteFb ------------------------
916{
918 if (m_pFramebuffer)
919 delete m_pFramebuffer;
920 return true;
921}
922
923//------------------ cOglCmdRenderFbToBufferFb --------------
925{
926 GLfloat x1 = m_x; // left
927 GLfloat y1 = m_y; // top
928 GLfloat x2 = m_x + m_pFramebuffer->ViewportWidth(); // right
929 GLfloat y2 = m_y + m_pFramebuffer->ViewportHeight(); // bottom
930
932 GLfloat texX2 = texX1 + 1.0f;
934 GLfloat texY2 = texY1 + 1.0f;
935
936 if (m_pFramebuffer->Scrollable()) {
942 }
943
945 // Pos // TexCoords
946 x1, y1, texX1, texY2, // left top
947 x1, y2, texX1, texY1, // left bottom
948 x2, y2, texX2, texY1, // right bottom
949
950 x1, y1, texX1, texY2, // left top
951 x2, y2, texX2, texY1, // right bottom
952 x2, y1, texX2, texY2 // right top
953 };
954
955 VertexBuffers[vbTexture]->ActivateShader();
956 VertexBuffers[vbTexture]->SetShaderAlpha(m_transparency);
957 VertexBuffers[vbTexture]->SetShaderProjectionMatrix(m_pBuffer->Width(), m_pBuffer->Height());
958 VertexBuffers[vbTexture]->SetShaderBorderColor(m_bcolor);
959
960 m_pBuffer->Bind();
962 return false;
963 if (!m_alphablending)
964 VertexBuffers[vbTexture]->DisableBlending();
965 VertexBuffers[vbTexture]->Bind();
968 VertexBuffers[vbTexture]->SetVertexSubData(quadVertices);
969 VertexBuffers[vbTexture]->DrawArrays();
971 VertexBuffers[vbTexture]->Unbind();
972
973 if (!m_alphablending)
974 VertexBuffers[vbTexture]->EnableBlending();
975 m_pBuffer->Unbind();
976
977 return true;
978}
979
980//------------------ cOglCmdCopyBufferToOutputFb ------------
982{
983 GLfloat x1 = m_x;
984 GLfloat y1 = m_y;
987
988 GLfloat texX1 = 0.0f;
989 GLfloat texX2 = 1.0f;
990 GLfloat texY1 = 1.0f;
991 GLfloat texY2 = 0.0f;
992
994 // Pos // TexCoords
995 x1, y1, texX1, texY1, //left top
996 x1, y2, texX1, texY2, //left bottom
997 x2, y2, texX2, texY2, //right bottom
998
999 x1, y1, texX1, texY1, //left top
1000 x2, y2, texX2, texY2, //right bottom
1001 x2, y1, texX2, texY1 //right top
1002 };
1003
1004 VertexBuffers[vbTexture]->ActivateShader();
1005 VertexBuffers[vbTexture]->SetShaderAlpha(255);
1007 VertexBuffers[vbTexture]->SetShaderBorderColor(m_borderColor);
1008
1012 return false;
1013
1014 VertexBuffers[vbTexture]->Bind();
1015 VertexBuffers[vbTexture]->SetVertexSubData(quadVertices);
1016 VertexBuffers[vbTexture]->DrawArrays();
1017 VertexBuffers[vbTexture]->Unbind();
1018
1019 GL_CHECK(glFinish());
1020 // eglSwapBuffers and gbm_surface_lock_front_buffer in OsdDrawARGB()
1021 if (m_active)
1023 else
1025
1027
1028 return true;
1029}
1030
1031//------------------ cOglCmdFill ----------------------------
1033{
1034 glm::vec4 col;
1037 GL_CHECK(glClearColor(col.r, col.g, col.b, col.a));
1040
1041 return true;
1042}
1043
1044//------------------ cOglCmdBufferFill ----------------------
1046{
1047 glm::vec4 col;
1049 GL_CHECK(glClearColor(col.r, col.g, col.b, col.a));
1051
1052 return true;
1053}
1054
1055//------------------ cOglCmdDrawRectangle -------------------
1057{
1058 if (m_width <= 0 || m_height <= 0)
1059 return false;
1060
1061 GLfloat x1 = m_x;
1062 GLfloat y1 = m_y;
1063 GLfloat x2 = m_x + m_width;
1064 GLfloat y2 = m_y + m_height;
1065
1066 GLfloat vertices[] = {
1067 x1, y1, // left top
1068 x2, y1, // right top
1069 x2, y2, // right bottom
1070 x1, y2 // left bottom
1071 };
1072
1073 VertexBuffers[vbRect]->ActivateShader();
1074 VertexBuffers[vbRect]->SetShaderColor(m_color);
1075 VertexBuffers[vbRect]->SetShaderProjectionMatrix(m_pFramebuffer->Width(), m_pFramebuffer->Height());
1076
1078 VertexBuffers[vbRect]->DisableBlending();
1079 VertexBuffers[vbRect]->Bind();
1080 VertexBuffers[vbRect]->SetVertexSubData(vertices);
1081 VertexBuffers[vbRect]->DrawArrays();
1082 VertexBuffers[vbRect]->Unbind();
1083 VertexBuffers[vbRect]->EnableBlending();
1085
1086 return true;
1087}
1088
1089//------------------ cOglCmdDrawEllipse ---------------------
1090// quadrants:
1091// 0 draws the entire ellipse
1092// 1..4 draws only the first, second, third or fourth quadrant, respectively
1093// 5..8 draws the right, top, left or bottom half, respectively
1094// -1..-4 draws the inverted part of the given quadrant
1095//-----------------------------------------------------------
1097{
1098 if (m_width <= 0 || m_height <= 0)
1099 return false;
1100
1101 int numVertices = 0;
1103
1104 switch (m_quadrants) {
1105 case 0:
1107 break;
1108 case 1:
1109 case 2:
1110 case 3:
1111 case 4:
1112 case -1:
1113 case -2:
1114 case -3:
1115 case -4:
1117 break;
1118 case 5:
1119 case 6:
1120 case 7:
1121 case 8:
1123 break;
1124 default:
1125 break;
1126 }
1127
1128 VertexBuffers[vbEllipse]->ActivateShader();
1129 VertexBuffers[vbEllipse]->SetShaderColor(m_color);
1130 VertexBuffers[vbEllipse]->SetShaderProjectionMatrix(m_pFramebuffer->Width(), m_pFramebuffer->Height());
1131
1132 // not antialiased
1134 VertexBuffers[vbEllipse]->DisableBlending();
1135 VertexBuffers[vbEllipse]->Bind();
1136 VertexBuffers[vbEllipse]->SetVertexSubData(vertices, numVertices);
1137 VertexBuffers[vbEllipse]->DrawArrays(numVertices);
1138 VertexBuffers[vbEllipse]->Unbind();
1139 VertexBuffers[vbEllipse]->EnableBlending();
1141
1142 delete[] vertices;
1143 return true;
1144}
1145
1147{
1148 int size = 364;
1149 numVertices = size/2;
1152 GLfloat *vertices = new GLfloat[size];
1153 vertices[0] = m_x + radiusX;
1154 vertices[1] = m_y + radiusY;
1155 for (int i=0; i <= 180; i++) {
1156 vertices[2 * i + 2] = m_x + radiusX + (GLfloat)cos(2 * i * M_PI / 180.0f) * radiusX;
1157 vertices[2 * i + 3] = m_y + radiusY - (GLfloat)sin(2 * i * M_PI / 180.0f) * radiusY;
1158 }
1159 return vertices;
1160}
1161
1163{
1164 int size = 94;
1165 numVertices = size / 2;
1168 GLint transX = 0;
1169 GLint transY = 0;
1170 GLint startAngle = 0;
1171 GLfloat *vertices = new GLfloat[size];
1172 switch (m_quadrants) {
1173 case 1:
1174 vertices[0] = m_x;
1175 vertices[1] = m_y + m_height;
1176 transY = radiusY;
1177 break;
1178 case 2:
1179 vertices[0] = m_x + m_width;
1180 vertices[1] = m_y + m_height;
1181 transX = radiusX;
1182 transY = radiusY;
1183 startAngle = 90;
1184 break;
1185 case 3:
1186 vertices[0] = m_x + m_width;
1187 vertices[1] = m_y;
1188 transX = radiusX;
1189 startAngle = 180;
1190 break;
1191 case 4:
1192 vertices[0] = m_x;
1193 vertices[1] = m_y;
1194 startAngle = 270;
1195 break;
1196 case -1:
1197 vertices[0] = m_x + m_width;
1198 vertices[1] = m_y;
1199 transY = radiusY;
1200 break;
1201 case -2:
1202 vertices[0] = m_x;
1203 vertices[1] = m_y;
1204 transX = radiusX;
1205 transY = radiusY;
1206 startAngle = 90;
1207 break;
1208 case -3:
1209 vertices[0] = m_x;
1210 vertices[1] = m_y + m_height;
1211 transX = radiusX;
1212 startAngle = 180;
1213 break;
1214 case -4:
1215 vertices[0] = m_x + m_width;
1216 vertices[1] = m_y + m_height;
1217 startAngle = 270;
1218 break;
1219 default:
1220 break;
1221 }
1222 for (int i = 0; i <= 45; i++) {
1223 vertices[2 * i + 2] = m_x + transX + (GLfloat)cos((2 * i + startAngle) * M_PI / 180.0f) * radiusX;
1224 vertices[2 * i + 3] = m_y + transY - (GLfloat)sin((2 * i + startAngle) * M_PI / 180.0f) * radiusY;
1225 }
1226 return vertices;
1227}
1228
1230{
1231 int size = 184;
1232 numVertices = size / 2;
1233 GLfloat radiusX = 0.0f;
1234 GLfloat radiusY = 0.0f;
1235 GLint transX = 0;
1236 GLint transY = 0;
1237 GLint startAngle = 0;
1238 GLfloat *vertices = new GLfloat[size];
1239 switch (m_quadrants) {
1240 case 5:
1242 radiusY = (GLfloat)m_height / 2;
1243 vertices[0] = m_x;
1244 vertices[1] = m_y + radiusY;
1245 startAngle = 270;
1246 transY = radiusY;
1247 break;
1248 case 6:
1249 radiusX = (GLfloat)m_width / 2;
1251 vertices[0] = m_x + radiusX;
1252 vertices[1] = m_y + radiusY;
1253 startAngle = 0;
1254 transX = radiusX;
1255 transY = radiusY;
1256 break;
1257 case 7:
1259 radiusY = (GLfloat)m_height / 2;
1260 vertices[0] = m_x + radiusX;
1261 vertices[1] = m_y + radiusY;
1262 startAngle = 90;
1263 transX = radiusX;
1264 transY = radiusY;
1265 break;
1266 case 8:
1267 radiusX = (GLfloat)m_width / 2;
1269 vertices[0] = m_x + radiusX;
1270 vertices[1] = m_y;
1271 startAngle = 180;
1272 transX = radiusX;
1273 break;
1274 default:
1275 break;
1276 }
1277 for (int i=0; i <= 90; i++) {
1278 vertices[2 * i + 2] = m_x + transX + (GLfloat)cos((2 * i + startAngle) * M_PI / 180.0f) * radiusX;
1279 vertices[2 * i + 3] = m_y + transY - (GLfloat)sin((2 * i + startAngle) * M_PI / 180.0f) * radiusY;
1280 }
1281 return vertices;
1282}
1283
1284//------------------ cOglCmdDrawSlope -----------------------
1285// type:
1286// 0: horizontal, rising, lower
1287// 1: horizontal, rising, upper
1288// 2: horizontal, falling, lower
1289// 3: horizontal, falling, upper
1290// 4: vertical, rising, lower
1291// 5: vertical, rising, upper
1292// 6: vertical, falling, lower
1293// 7: vertical, falling, upper
1294//-----------------------------------------------------------
1296{
1297 if (m_width <= 0 || m_height <= 0)
1298 return false;
1299
1300 bool falling = m_type & 0x02;
1301 bool vertical = m_type & 0x04;
1302
1303 int steps = 100;
1304 if (m_width < 100)
1305 steps = 25;
1306 int numVertices = steps + 2;
1307 GLfloat *vertices = new GLfloat[numVertices * 2];
1308
1309 switch (m_type) {
1310 case 0:
1311 case 4:
1312 vertices[0] = (GLfloat)(m_x + m_width);
1313 vertices[1] = (GLfloat)(m_y + m_height);
1314 break;
1315 case 1:
1316 case 5:
1317 vertices[0] = (GLfloat)m_x;
1318 vertices[1] = (GLfloat)m_y;
1319 break;
1320 case 2:
1321 case 6:
1322 vertices[0] = (GLfloat)m_x;
1323 vertices[1] = (GLfloat)(m_y + m_height);
1324 break;
1325 case 3:
1326 case 7:
1327 vertices[0] = (GLfloat)(m_x + m_width);
1328 vertices[1] = (GLfloat)m_y;
1329 break;
1330 default:
1331 vertices[0] = (GLfloat)(m_x);
1332 vertices[1] = (GLfloat)(m_y);
1333 break;
1334 }
1335
1336 for (int i = 0; i <= steps; i++) {
1337 GLfloat c = cos(i * M_PI / steps);
1338 if (falling)
1339 c = -c;
1340 if (vertical) {
1341 vertices[2 * i + 2] = (GLfloat)m_x + (GLfloat)m_width / 2.0f + (GLfloat)m_width * c / 2.0f;
1342 vertices[2 * i + 3] = (GLfloat)m_y + (GLfloat)i * ((GLfloat)m_height) / steps ;
1343 } else {
1344 vertices[2 * i + 2] = (GLfloat)m_x + (GLfloat)i * ((GLfloat)m_width) / steps ;
1345 vertices[2 * i + 3] = (GLfloat)m_y + (GLfloat)m_height / 2.0f + (GLfloat)m_height * c / 2.0f;
1346 }
1347 }
1348
1349 VertexBuffers[vbSlope]->ActivateShader();
1350 VertexBuffers[vbSlope]->SetShaderColor(m_color);
1351 VertexBuffers[vbSlope]->SetShaderProjectionMatrix(m_pFramebuffer->Width(), m_pFramebuffer->Height());
1352
1353 // not antialiased
1355 VertexBuffers[vbSlope]->DisableBlending();
1356 VertexBuffers[vbSlope]->Bind();
1357 VertexBuffers[vbSlope]->SetVertexSubData(vertices, numVertices);
1358 VertexBuffers[vbSlope]->DrawArrays(numVertices);
1359 VertexBuffers[vbSlope]->Unbind();
1360 VertexBuffers[vbSlope]->EnableBlending();
1362
1363 delete[] vertices;
1364 return true;
1365}
1366
1367//------------------ cOglCmdDrawText ------------------------
1369{
1371 if (!f)
1372 return false;
1373
1374 if (!m_length)
1375 return false;
1376
1377 VertexBuffers[vbText]->ActivateShader();
1378 VertexBuffers[vbText]->SetShaderColor(m_colorText);
1379 VertexBuffers[vbText]->SetShaderProjectionMatrix(m_pFramebuffer->Width(), m_pFramebuffer->Height());
1380
1382 VertexBuffers[vbText]->Bind();
1383
1384 int xGlyph = m_x;
1385 int yGlyph = m_y;
1386 int fontHeight = f->Height();
1387 int bottom = f->Bottom();
1388 FT_ULong sym = 0;
1389 FT_ULong prevSym = 0;
1390 int kerning = 0;
1391
1392 // Check, if we only have symbols, which are in our atlas
1393 int unknown_char = 0;
1394 for (int i = 0; m_pSymbols[i]; i++) {
1395 if ((m_pSymbols[i] < MIN_CHARCODE) || (m_pSymbols[i] > MAX_CHARCODE)) {
1396 if (m_pSymbols[i]) {
1398 break;
1399 }
1400 }
1401 }
1402
1403 if (!unknown_char) {
1404 cOglFontAtlas *fa = f->Atlas();
1405 std::vector<GLfloat> vertices;
1406 vertices.reserve( 4 * 6 * m_length);
1407
1408 for (int i = 0; m_pSymbols[i]; i++) {
1409 sym = m_pSymbols[i];
1410
1412 // Get the glyph from the font atlas for ASCII code MIN_CHARCODE-MAX_CHARCODE
1413 g = fa->GetGlyph(sym);
1414
1415 if (!g) {
1416 LOGWARNING("openglosd: %s: could not load glyph %lx", __FUNCTION__, sym);
1417 continue;
1418 }
1419
1420 if ( m_limitX && xGlyph + g->AdvanceX() > m_limitX )
1421 break;
1422
1423 kerning = f->Kerning(g, prevSym);
1424 prevSym = sym;
1425
1426 GLfloat x2 = xGlyph + kerning + g->BearingLeft();
1427 GLfloat y2 = m_y + (fontHeight - bottom - g->BearingTop()); //top
1428 GLfloat w = g->Width();
1429 GLfloat h = g->Height();
1430
1431 vertices.push_back(x2);
1432 vertices.push_back(y2);
1433 vertices.push_back(g->OffsetX());
1434 vertices.push_back(g->OffsetY());
1435
1436 vertices.push_back(x2 + w);
1437 vertices.push_back(y2);
1438 vertices.push_back(g->OffsetX() + g->Width() / (float)fa->Width());
1439 vertices.push_back(g->OffsetY());
1440
1441 vertices.push_back(x2);
1442 vertices.push_back(y2 + h);
1443 vertices.push_back(g->OffsetX());
1444 vertices.push_back(g->OffsetY() + g->Height() / (float)fa->Height());
1445
1446 vertices.push_back(x2 + w);
1447 vertices.push_back(y2);
1448 vertices.push_back(g->OffsetX() + g->Width() / (float)fa->Width());
1449 vertices.push_back(g->OffsetY());
1450
1451 vertices.push_back(x2);
1452 vertices.push_back(y2 + h);
1453 vertices.push_back(g->OffsetX());
1454 vertices.push_back(g->OffsetY() + g->Height() / (float)fa->Height());
1455
1456 vertices.push_back(x2 + w);
1457 vertices.push_back(y2 + h);
1458 vertices.push_back(g->OffsetX() + g->Width() / (float)fa->Width());
1459 vertices.push_back(g->OffsetY() + g->Height() / (float)fa->Height());
1460
1461 xGlyph += kerning + g->AdvanceX();
1462 yGlyph += kerning + g->AdvanceY();
1463
1464
1465 if ( xGlyph > m_pFramebuffer->Width() - 1 )
1466 break;
1467 }
1468
1469 fa->BindTexture();
1470 VertexBuffers[vbText]->SetVertexData(vertices.data(), (vertices.size() / 4));
1471 VertexBuffers[vbText]->DrawArrays(vertices.size() / 4);
1472 } else {
1473 LOGDEBUG2(L_OPENGL, "openglosd: %s: char %d is not on the texture atlas, use single draw", __FUNCTION__, unknown_char);
1474 for (int i = 0; m_pSymbols[i]; i++) {
1475 sym = m_pSymbols[i];
1476 cOglGlyph *g = f->Glyph(sym);
1477 if (!g) {
1478 LOGWARNING("openglosd: %s: could not load glyph %lx", __FUNCTION__, sym);
1479 continue;
1480 }
1481
1482 if ( m_limitX && xGlyph + g->AdvanceX() > m_limitX )
1483 break;
1484
1485 kerning = f->Kerning(g, prevSym);
1486 prevSym = sym;
1487
1488 GLfloat x1 = xGlyph + kerning + g->BearingLeft(); // left
1489 GLfloat y1 = m_y + (fontHeight - bottom - g->BearingTop()); // top
1490 GLfloat x2 = x1 + g->Width(); // right
1491 GLfloat y2 = y1 + g->Height(); // bottom
1492
1493 GLfloat vertices[] = {
1494 x1, y2, 0.0, 1.0, // left bottom
1495 x1, y1, 0.0, 0.0, // left top
1496 x2, y1, 1.0, 0.0, // right top
1497
1498 x1, y2, 0.0, 1.0, // left bottom
1499 x2, y1, 1.0, 0.0, // right top
1500 x2, y2, 1.0, 1.0 // right bottom
1501 };
1502
1503 g->BindTexture();
1504 VertexBuffers[vbText]->SetVertexData(vertices);
1505 VertexBuffers[vbText]->DrawArrays();
1506
1507 xGlyph += kerning + g->AdvanceX();
1508
1509 if ( xGlyph > m_pFramebuffer->Width() - 1 )
1510 break;
1511 }
1512 }
1513
1515 VertexBuffers[vbText]->Unbind();
1517 return true;
1518}
1519
1520//------------------ cOglCmdDrawImage -----------------------
1522{
1523 if (m_width <= 0 || m_height <= 0)
1524 return false;
1525
1526 GLuint texture;
1527 GL_CHECK(glGenTextures(1, &texture));
1531 0,
1532 GL_RGBA,
1533 m_width,
1534 m_height,
1535 0,
1536 GL_RGBA,
1538 m_argb
1539 ));
1545
1546 GLfloat x1 = m_x; // left
1547 GLfloat y1 = m_y; // top
1548 GLfloat x2 = m_x + m_width * m_scaleX; // right
1549 GLfloat y2 = m_y + m_height * m_scaleY; // bottom
1550
1551 GLfloat quadVertices[] = {
1552 x1, y2, 0.0, 1.0, // left bottom
1553 x1, y1, 0.0, 0.0, // left top
1554 x2, y1, 1.0, 0.0, // right top
1555
1556 x1, y2, 0.0, 1.0, // left bottom
1557 x2, y1, 1.0, 0.0, // right top
1558 x2, y2, 1.0, 1.0 // right bottom
1559 };
1560
1561 VertexBuffers[vbTextureSwapBR]->ActivateShader();
1562 VertexBuffers[vbTextureSwapBR]->SetShaderAlpha(255);
1563 VertexBuffers[vbTextureSwapBR]->SetShaderProjectionMatrix(m_pFramebuffer->Width(), m_pFramebuffer->Height());
1564 VertexBuffers[vbTextureSwapBR]->SetShaderBorderColor(m_borderColor);
1565
1568 if (m_overlay)
1569 VertexBuffers[vbTextureSwapBR]->DisableBlending();
1571 VertexBuffers[vbTextureSwapBR]->SetVertexSubData(quadVertices);
1572 VertexBuffers[vbTextureSwapBR]->DrawArrays();
1573 VertexBuffers[vbTextureSwapBR]->Unbind();
1574 if (m_overlay)
1575 VertexBuffers[vbTextureSwapBR]->EnableBlending();
1578 GL_CHECK(glDeleteTextures(1, &texture));
1579
1580 return true;
1581}
1582
1583//------------------ cOglCmdDrawTexture ---------------------
1585{
1586 if (m_pImageRef->width <= 0 || m_pImageRef->height <= 0)
1587 return false;
1588
1589 GLfloat x1 = m_x; // top
1590 GLfloat y1 = m_y; // left
1591 GLfloat x2 = m_x + m_pImageRef->width * m_scaleX; // right
1592 GLfloat y2 = m_y + m_pImageRef->height * m_scaleY; // bottom
1593
1594 GLfloat quadVertices[] = {
1595 // Pos // TexCoords
1596 x1, y1, 0.0f, 0.0f, // left bottom
1597 x1, y2, 0.0f, 1.0f, // left top
1598 x2, y2, 1.0f, 1.0f, // right top
1599
1600 x1, y1, 0.0f, 0.0f, // left bottom
1601 x2, y2, 1.0f, 1.0f, // right top
1602 x2, y1, 1.0f, 0.0f // right bottom
1603 };
1604
1605 VertexBuffers[vbTextureSwapBR]->ActivateShader();
1606 VertexBuffers[vbTextureSwapBR]->SetShaderAlpha(255);
1607 VertexBuffers[vbTextureSwapBR]->SetShaderProjectionMatrix(m_pFramebuffer->Width(), m_pFramebuffer->Height());
1608 VertexBuffers[vbTextureSwapBR]->SetShaderBorderColor(m_borderColor);
1609
1613 VertexBuffers[vbTextureSwapBR]->SetVertexSubData(quadVertices);
1614 VertexBuffers[vbTextureSwapBR]->DrawArrays();
1615 VertexBuffers[vbTextureSwapBR]->Unbind();
1617
1618 return true;
1619}
1620
1621//------------------ cOglCmdStoreImage ----------------------
1643
1644//------------------ cOglCmdDropImage -----------------------
1646 if (m_pImageRef->texture != GL_NONE)
1648 m_pWait->Signal();
1649 return true;
1650}
1651
1652/******************************************************************************
1653 * cOglThread
1654 *****************************************************************************/
1656 : cThread("oglThread"),
1657 m_startWait(startWait),
1658 m_maxCacheSize(maxCacheSize * 1024 * 1024),
1659 m_pRender(device->Render())
1660{
1661 for (int i = 0; i < OGL_MAX_OSDIMAGES; i++) {
1662 m_imageCache[i].used = false;
1664 m_imageCache[i].width = 0;
1665 m_imageCache[i].height = 0;
1666 }
1667
1668 Start();
1669}
1670
1672{
1673 for (int i = 0; i < OGL_MAX_OSDIMAGES; i++) {
1674 if (m_imageCache[i].used) {
1676 }
1677 }
1678}
1679
1681{
1683 Cancel(-1);
1684}
1685
1687{
1689 Cancel(2);
1690 Cleanup();
1691 m_stalled = false;
1692}
1693
1695{
1696 while (m_stalled)
1697 cCondWait::SleepMs(10);
1698
1699 bool doSignal = false;
1700 Lock();
1701 if (m_commands.size() == 0)
1702 doSignal = true;
1703 m_commands.push(cmd);
1704 Unlock();
1705
1706 if (m_commands.size() > OGL_CMDQUEUE_SIZE) {
1707 m_stalled = true;
1708 }
1709
1710 if (doSignal || m_stalled)
1711 m_wait.Signal();
1712}
1713
1715{
1716 if (!m_maxCacheSize) {
1717 LOGERROR("openglosd: %s: cannot store image, no cache set", __FUNCTION__);
1718 return 0;
1719 }
1720
1721 if (image.Width() > m_maxTextureSize || image.Height() > m_maxTextureSize) {
1722 LOGERROR("openglosd: %s: cannot store image of %dpx x %dpx (maximum size is %dpx x %dpx) - falling back to cOsdProvider::StoreImageData()",
1724 return 0;
1725 }
1726
1727 int imgSize = image.Width() * image.Height();
1728 int newMemUsed = imgSize * sizeof(tColor) + m_memCached;
1729 if (newMemUsed > m_maxCacheSize) {
1730 float cachedMB = m_memCached / 1024.0f / 1024.0f;
1731 float maxMB = m_maxCacheSize / 1024.0f / 1024.0f;
1732 LOGERROR("openglosd: %s: Maximum size for GPU cache reached. Used: %.2fMB Max: %.2fMB", __FUNCTION__, cachedMB, maxMB);
1733 return 0;
1734 }
1735
1736 int slot = GetFreeSlot();
1737 if (!slot)
1738 return 0;
1739
1741 if (!argb) {
1742 LOGERROR("openglosd: %s: memory allocation of %d kb for OSD image failed", __FUNCTION__, (int)(imgSize * sizeof(tColor) / 1024));
1743 ClearSlot(slot);
1744 slot = 0;
1745 return 0;
1746 }
1747
1748 memcpy(argb, image.Data(), sizeof(tColor) * imgSize);
1749
1751 imageRef->width = image.Width();
1752 imageRef->height = image.Height();
1754
1755 cTimeMs timer(5000);
1756 while (imageRef->used && imageRef->texture == 0 && !timer.TimedOut())
1757 cCondWait::SleepMs(2);
1758
1759 if (imageRef->texture == GL_NONE) {
1760 LOGERROR("openglosd: %s: failed to store OSD image texture! (%s)", __FUNCTION__, timer.TimedOut() ? "timed out" : "allocation failed");
1762 slot = 0;
1763 }
1764
1765 m_memCached += imgSize * sizeof(tColor);
1766
1767 return slot;
1768}
1769
1771{
1772 Lock();
1773 int slot = 0;
1774 for (int i = 0; i < OGL_MAX_OSDIMAGES && !slot; i++) {
1775 if (!m_imageCache[i].used) {
1776 m_imageCache[i].used = true;
1777 slot = -i - 1;
1778 }
1779 }
1780 Unlock();
1781 return slot;
1782}
1783
1785{
1786 int i = -slot - 1;
1787 if (i >= 0 && i < OGL_MAX_OSDIMAGES) {
1788 Lock();
1789 m_imageCache[i].used = false;
1791 m_imageCache[i].width = 0;
1792 m_imageCache[i].height = 0;
1793 Unlock();
1794 }
1795}
1796
1798{
1799 int i = -slot - 1;
1800 if (0 <= i && i < OGL_MAX_OSDIMAGES)
1801 return &m_imageCache[i];
1802 return 0;
1803}
1804
1806{
1808 if (!imageRef)
1809 return;
1810 int imgSize = imageRef->width * imageRef->height * sizeof(tColor);
1814 dropWait.Wait();
1816}
1817
1819{
1820 if (!InitOpenGL()) {
1821 LOGERROR("openglosd: %s: Could not initiate OpenGL context", __FUNCTION__);
1822 Cleanup();
1823 m_startWait->Signal();
1824 return;
1825 }
1826
1827 if (!InitShaders()) {
1828 LOGERROR("openglosd: %s: Could not initiate shaders", __FUNCTION__);
1829 Cleanup();
1830 m_startWait->Signal();
1831 return;
1832 }
1833
1834 if (!InitVertexBuffers()) {
1835 LOGERROR("openglosd: %s: Vertex Buffers NOT initialized", __FUNCTION__);
1836 Cleanup();
1837 m_startWait->Signal();
1838 return;
1839 }
1840
1842 LOGDEBUG2(L_OPENGL, "openglosd: %s: Maximum Pixmap size: %dx%dpx", __FUNCTION__, m_maxTextureSize, m_maxTextureSize);
1843
1844 //now Thread is ready to do his job
1845 m_startWait->Signal();
1846 m_stalled = false;
1847
1848 LOGINFO("OpenGL context initialized");
1849
1850 uint64_t startFlush = 0;
1851 uint64_t endFlush = 0;
1852 bool timeReset = false;
1853
1854 while(Running()) {
1855 if (m_commands.empty()) {
1856 m_wait.Wait(20);
1857 continue;
1858 }
1859
1860 Lock();
1861 cOglCmd* cmd = m_commands.front();
1862 m_commands.pop();
1863 Unlock();
1864
1865 uint64_t start = cTimeMs::Now();
1866 if (strcmp(cmd->Description(), "InitFramebuffer") == 0 || timeReset) {
1867 startFlush = cTimeMs::Now();
1868 timeReset = false;
1869 }
1870
1871 { // start of locked context
1872 std::unique_lock<std::mutex> lock(m_mutex, std::defer_lock);
1873
1874 if (cmd->NeedsLockingAgainstStateChange())
1875 lock.lock();
1876
1877 if (!Running())
1878 continue;
1879
1880 cmd->Execute();
1881 } // end of locked context
1882
1883 LOGDEBUG2(L_OPENGL_TIME_ALL, "openglosd: %s: \"%-*s\", %dms, %d commands left, time %" PRIu64 "",
1884 __FUNCTION__, 15, cmd->Description(), (int)(cTimeMs::Now() - start), (int)(m_commands.size()), cTimeMs::Now());
1885
1886 if (strcmp(cmd->Description(), "Copy buffer to OutputFramebuffer") == 0) {
1887 endFlush = cTimeMs::Now();
1888 timeReset = true;
1889 LOGDEBUG2(L_OPENGL_TIME, "openglosd: %s: OSD Flush %dms, time %" PRIu64 "", __FUNCTION__, (int)(endFlush - startFlush), cTimeMs::Now());
1890 }
1891 delete cmd;
1892 if (m_stalled && m_commands.size() < OGL_CMDQUEUE_SIZE / 2)
1893 m_stalled = false;
1894 }
1895
1896 LOGINFO("OpenGL worker thread stopped");
1897}
1898
1903
1909{
1910 LOGDEBUG2(L_OPENGL, "openglosd: %s: Init OpenGL context", __FUNCTION__);
1911
1912 // Wait for the EGL context to be created
1913 while(!m_pRender || !m_pRender->GlInitiated()) {
1914 LOGDEBUG2(L_OPENGL, "openglosd: %s: wait for EGL context", __FUNCTION__);
1915 usleep(20000);
1916 }
1917
1918 eglAcquireContext(); // eglMakeCurrent with new eglSurface
1919
1920 GL_CHECK(LOGDEBUG2(L_OPENGL, " GL Version: \"%s\"", glGetString(GL_VERSION)));
1921 GL_CHECK(LOGDEBUG2(L_OPENGL, " GL Vendor: \"%s\"", glGetString(GL_VENDOR)));
1922 GL_CHECK(LOGDEBUG2(L_OPENGL, " GL Extensions: \"%s\"", glGetString(GL_EXTENSIONS)));
1923 GL_CHECK(LOGDEBUG2(L_OPENGL, " GL Renderer: \"%s\"", glGetString(GL_RENDERER)));
1924
1925 VertexBuffers[vbText]->EnableBlending();
1927 LOGDEBUG2(L_OPENGL, "openglosd: %s: Init OpenGL context done", __FUNCTION__);
1928
1929 return true;
1930}
1931
1933{
1934 for (int i = 0; i < stCount; i++) {
1935 cOglShader *shader = new cOglShader();
1936 if (!shader->Load((eShaderType)i))
1937 return false;
1938 Shaders[i] = shader;
1939 }
1940 LOGDEBUG2(L_OPENGL, "openglosd: %s: Shaders initialized", __FUNCTION__);
1941
1942 return true;
1943}
1944
1946{
1947 for (int i = 0; i < stCount; i++)
1948 delete Shaders[i];
1949}
1950
1952{
1953 for (int i = 0; i < vbCount; i++) {
1954 cOglVb *vb = new cOglVb(i);
1955 if (!vb->Init())
1956 return false;
1957 VertexBuffers[i] = vb;
1958 }
1959 LOGDEBUG2(L_OPENGL, "openglosd: %s: Vertex buffers initialized", __FUNCTION__);
1960
1961 return true;
1962}
1963
1965{
1966 for (int i=0; i < vbCount; i++) {
1967 delete VertexBuffers[i];
1968 }
1969}
1970
1972{
1973 LOGDEBUG2(L_OPENGL, "openglosd: %s: Cleaning up OpenGL stuff", __FUNCTION__);
1974
1978 DeleteShaders();
1980}
1981
1982/******************************************************************************
1983 * cOglPixmap
1984 *****************************************************************************/
1985cOglPixmap::cOglPixmap(std::shared_ptr<cOglThread> oglThread, int layer, const cRect &viewPort, const cRect &drawPort)
1986 : cPixmap(layer, viewPort, drawPort),
1987 m_pOglThread(oglThread)
1988{
1989 int width = drawPort.IsEmpty() ? viewPort.Width() : drawPort.Width();
1990 int height = drawPort.IsEmpty() ? viewPort.Height() : drawPort.Height();
1991
1992 if (width > m_pOglThread->MaxTextureSize() || height > m_pOglThread->MaxTextureSize()) {
1993 LOGWARNING("openglosd: %s: cannot allocate pixmap of %dpx x %dpx, clipped to %dpx x %dpx!", __FUNCTION__,
1994 width, height, std::min(width, m_pOglThread->MaxTextureSize()), std::min(height, m_pOglThread->MaxTextureSize()));
1995 width = std::min(width, m_pOglThread->MaxTextureSize());
1996 height = std::min(height, m_pOglThread->MaxTextureSize());
1997 }
1998
1999 m_pFramebuffer = new cOglFb(width, height, viewPort.Width(), viewPort.Height());
2000
2001#ifdef GRIDPOINTS
2002 // Creates a tiny font with height GRIDPOINTSTXTSIZE
2003 m_pTinyfont = cFont::CreateFont(Setup.FontOsd, GRIDPOINTSTXTSIZE);
2004#endif
2005}
2006
2008{
2009 if (!m_pOglThread->Active())
2010 return;
2011
2013#ifdef GRIDPOINTS
2014 delete m_pTinyfont;
2015#endif
2016}
2017
2019{
2020 cPixmap::MarkViewPortDirty(rect);
2021 SetDirty();
2022}
2023
2025{
2026 cPixmap::SetClean();
2027 SetDirty(false);
2028}
2029
2031{
2032 cPixmap::SetLayer(layer);
2033 SetDirty();
2034}
2035
2037{
2039 if (alpha != cPixmap::Alpha()) {
2040 cPixmap::SetAlpha(alpha);
2041 SetDirty();
2042 }
2043}
2044
2046{
2047 cPixmap::SetTile(tile);
2048 SetDirty();
2049}
2050
2052{
2053 cPixmap::SetViewPort(rect);
2054 SetDirty();
2055}
2056
2058{
2059 cPixmap::SetDrawPortPoint(point, dirty);
2060 if (dirty)
2061 SetDirty();
2062}
2063
2065{
2066 if (!m_pOglThread->Active())
2067 return;
2068
2071 SetDirty();
2073}
2074
2076{
2077 if (!m_pOglThread->Active())
2078 return;
2079
2082 SetDirty();
2084}
2085
2087{
2089}
2090
2095
2096void cOglPixmap::DrawScaledImage(const cPoint &point, const cImage &image, double factorX, double factorY, __attribute__ ((unused)) bool antiAlias)
2097{
2098 if (!m_pOglThread->Active())
2099 return;
2100
2101 tColor *argb = MALLOC(tColor, image.Width() * image.Height());
2102 if (!argb)
2103 return;
2104 memcpy(argb, image.Data(), sizeof(tColor) * image.Width() * image.Height());
2105
2106 m_pOglThread->DoCmd(new cOglCmdDrawImage(m_pFramebuffer, argb, image.Width(), image.Height(), point.X(), point.Y(), true, factorX, factorY));
2107#ifdef GRIDRECT
2109#endif
2110 SetDirty();
2111 MarkDrawPortDirty(cRect(point, cSize(image.Width() * factorX, image.Height() * factorY)).Intersected(DrawPort().Size()));
2112}
2113
2115{
2116 if (!m_pOglThread->Active())
2117 return;
2118
2120 sOglImage *img = m_pOglThread->GetImageRef(imageHandle);
2122#ifdef GRIDRECT
2124#endif
2125 SetDirty();
2126 MarkDrawPortDirty(cRect(point, cSize(img->width * factorX, img->height * factorY)).Intersected(DrawPort().Size()));
2127 }
2128}
2129
2131{
2132 cRect r(point.X(), point.Y(), 1, 1);
2133 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, r.X(), r.Y(), r.Width(), r.Height(), color));
2134#ifdef GRIDRECT
2136#endif
2137 SetDirty();
2139}
2140
2142{
2143 if (!m_pOglThread->Active())
2144 return;
2145
2147 bool specialColors = colorFg || colorBg;
2148 tColor *argb = MALLOC(tColor, bitmap.Width() * bitmap.Height());
2149 if (!argb)
2150 return;
2151
2152 tColor *p = argb;
2153 for (int py = 0; py < bitmap.Height(); py++)
2154 for (int px = 0; px < bitmap.Width(); px++) {
2155 tIndex index = *bitmap.Data(px, py);
2156 *p++ = (!index && overlay) ? clrTransparent :
2157 (specialColors ? (index == 0 ? colorBg : index == 1 ? colorFg :
2158 bitmap.Color(index)) : bitmap.Color(index));
2159 }
2160
2161 m_pOglThread->DoCmd(new cOglCmdDrawImage(m_pFramebuffer, argb, bitmap.Width(), bitmap.Height(), point.X(), point.Y(), true));
2162#ifdef GRIDRECT
2164#endif
2165
2166 SetDirty();
2167 MarkDrawPortDirty(cRect(cPoint(point.X(), point.Y()), cSize(bitmap.Width(), bitmap.Height())).Intersected(DrawPort().Size()));
2168}
2169
2170void cOglPixmap::DrawText(const cPoint &point, const char *s, tColor colorFg, tColor colorBg, const cFont *font, int width, int height, int alignment)
2171{
2172 DrawTextInternal(point, s, colorFg, colorBg, font, width, height, alignment, false);
2173}
2174
2175#ifdef GRIDPOINTS
2176void cOglPixmap::DrawGridText(const cPoint &point, const char *s, tColor colorFg, tColor colorBg, const cFont *font, int width, int height, int alignment)
2177{
2178 DrawTextInternal(point, s, colorFg, colorBg, font, width, height, alignment, true);
2179}
2180#endif
2181
2182void cOglPixmap::DrawTextInternal(const cPoint &point, const char *s, tColor colorFg, tColor colorBg, const cFont *font, int width, int height, int alignment, bool isGridText)
2183{
2184 if (!m_pOglThread->Active())
2185 return;
2186
2188 int len = s ? Utf8StrLen(s) : 0;
2189 unsigned int *symbols = MALLOC(unsigned int, len + 1);
2190 if (!symbols)
2191 return;
2192
2193 if (len)
2194 Utf8ToArray(s, symbols, len + 1);
2195 else
2196 symbols[0] = 0;
2197
2198 int x = point.X();
2199 int y = point.Y();
2200 int w = font->Width(s);
2201 int h = font->Height();
2202 int limitX = 0;
2203 int cw = width ? width : w;
2204 int ch = height ? height : h;
2205
2206 // workaround for messages in SkinElchiHD
2207 if (width > ViewPort().Width() && !x && !isGridText)
2208 x = ViewPort().Width() - w;
2209
2210 cRect r(x, y, cw, ch);
2211
2212 if (colorBg != clrTransparent)
2213 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, r.X(), r.Y(), r.Width(), r.Height(), colorBg));
2214
2215 if (width || height)
2216 limitX = x + cw;
2217
2218 if (width) {
2219 if ((alignment & taLeft) != 0) {
2220 if ((alignment & taBorder) != 0)
2221 x += std::max(h / TEXT_ALIGN_BORDER, 1);
2222 } else if ((alignment & taRight) != 0) {
2223 if (w < width)
2224 x += width - w;
2225 if ((alignment & taBorder) != 0)
2226 x -= std::max(h / TEXT_ALIGN_BORDER, 1);
2227 } else { // taCentered
2228 if (w < width)
2229 x += (width - w) / 2;
2230 }
2231 }
2232
2233 if (height) {
2234 if ((alignment & taTop) != 0)
2235 ;
2236 else if ((alignment & taBottom) != 0) {
2237 if (h < height)
2238 y += height - h;
2239 } else { // taCentered
2240 if (h < height)
2241 y += (height - h) / 2;
2242 }
2243 }
2244
2245 m_pOglThread->DoCmd(new cOglCmdDrawText(m_pFramebuffer, x, y, symbols, limitX, font->FontName(), font->Size(), colorFg, len));
2246
2247#ifdef GRIDTEXT
2248 if (!isGridText)
2250#endif
2251
2252 SetDirty();
2254}
2255
2257{
2258 if (!m_pOglThread->Active())
2259 return;
2260
2262 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, rect.X(), rect.Y(), rect.Width(), rect.Height(), color));
2263#ifdef GRIDRECT
2265#endif
2266
2267 SetDirty();
2269}
2270
2272{
2273 if (!m_pOglThread->Active())
2274 return;
2275
2277 m_pOglThread->DoCmd(new cOglCmdDrawEllipse(m_pFramebuffer, rect.X(), rect.Y(), rect.Width(), rect.Height(), color, quadrants));
2278#ifdef GRIDRECT
2280#endif
2281
2282 SetDirty();
2284}
2285
2287{
2288 if (!m_pOglThread->Active())
2289 return;
2290
2292 m_pOglThread->DoCmd(new cOglCmdDrawSlope(m_pFramebuffer, rect.X(), rect.Y(), rect.Width(), rect.Height(), color, type));
2293#ifdef GRIDRECT
2295#endif
2296
2297 SetDirty();
2299}
2300
2301void cOglPixmap::Render(const cPixmap *pixmap, const cRect &source, const cPoint &dest)
2302{
2303 LOGWARNING("openglosd: %s: %d %d %d not implemented in OpenGl OSD", __FUNCTION__, pixmap->ViewPort().X(), source.X(), dest.X());
2304}
2305
2306void cOglPixmap::Copy(const cPixmap *pixmap, const cRect &source, const cPoint &dest)
2307{
2308 LOGWARNING("openglosd: %s: %d %d %d not implemented in OpenGl OSD", __FUNCTION__, pixmap->ViewPort().X(), source.X(), dest.X());
2309}
2310
2312{
2313 LOGWARNING("openglosd: %s: %d %d not implemented in OpenGl OSD", __FUNCTION__, source.X(), dest.X());
2314}
2315
2317{
2318 LOGWARNING("openglosd: %s: %d %d not implemented in OpenGl OSD", __FUNCTION__, source.X(), dest.X());
2319}
2320
2321#ifdef GRIDPOINTS
2322void cOglPixmap::DrawGridRect(const cRect &rect, int offset, int size, tColor clr, tColor bg, const cFont *font)
2323{
2324 int x1 = rect.X() + offset;
2325 int x2 = rect.X() + rect.Width() + offset;
2326 int y1 = rect.Y();
2327 int y2 = rect.Y() + rect.Height();
2328 char p1[10];
2329 char p2[10];
2330 char p3[10];
2331 char p4[10];
2332 sprintf(p1, "%d.%d", x1, y1);
2333 sprintf(p2, "%d.%d", x2, y1);
2334 sprintf(p3, "%d.%d", x1, y2);
2335 sprintf(p4, "%d.%d", x2, y2);
2336
2337 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, x1, y1, size, size, clr));
2338#ifdef GRIDPOINTSTEXT
2340#endif
2341 if (Rect.Width() && Rect.Height()) {
2342 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, x2, y1, size, size, clr));
2343 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, x1, y2, size, size, clr));
2344 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, x2, y2, size, size, clr));
2345#ifdef GRIDPOINTSTEXT
2349#endif
2350 }
2351}
2352#endif
2353
2354/******************************************************************************
2355 * cOglOsd
2356 *****************************************************************************/
2358
2359cOglOsd::cOglOsd(int left, int top, uint level, std::shared_ptr<cOglThread> oglThread, cSoftHdDevice *device)
2360 : cOsd(left, top, level),
2361 m_pOglThread(oglThread),
2362 m_isSubtitleOsd(level == 10 ? true : false),
2363 m_pDevice(device)
2364{
2365 int osdWidth = 0;
2366 int osdHeight = 0;
2367 double pixelAspect;
2369 LOGDEBUG2(L_OSD, "openglosd: %s: New Osd %p osdLeft %d osdTop %d screenWidth %d screenHeight %d", __FUNCTION__, this, left, top, osdWidth, osdHeight);
2370
2371 m_maxPixmapSize.Set(m_pOglThread->MaxTextureSize(), m_pOglThread->MaxTextureSize());
2372
2373 if (!OutputFramebuffer) {
2376 }
2377}
2378
2380{
2381 if (!m_pOglThread->Active() || !Active() || !m_pBufferFramebuffer)
2382 return;
2383
2384 LOGDEBUG2(L_OSD, "openglosd: %s: Delete Osd %p", __FUNCTION__, this);
2386
2387 SetActive(false); // OsdClose() is done in cOglCmdCopyBufferToOutputFb()
2390}
2391
2393{
2394 cRect r;
2395 if (numAreas > 1)
2396 m_isSubtitleOsd = true;
2397 for (int i = 0; i < numAreas; i++)
2398 r.Combine(cRect(areas[i].x1, areas[i].y1, areas[i].Width(), areas[i].Height()));
2399
2400 tArea area = { r.Left(), r.Top(), r.Right(), r.Bottom(), 32 };
2401
2402 // now we know the actual osd size, create double buffer frame buffer
2406 }
2407 m_pBufferFramebuffer = new cOglFb(r.Width(), r.Height(), r.Width(), r.Height());
2410 initiated.Wait();
2411
2412 return cOsd::SetAreas(&area, 1);
2413}
2414
2416{
2417 if (!m_pOglThread->Active())
2418 return NULL;
2419
2422 if (cOsd::AddPixmap(p)) {
2423 // find a free slot
2424 for (int i = 0; i < m_pOglPixmaps.Size(); i++) {
2425 if (!m_pOglPixmaps[i])
2426 return m_pOglPixmaps[i] = p;
2427 }
2428 m_pOglPixmaps.Append(p);
2429 return p;
2430 }
2431 delete p;
2432
2433 return NULL;
2434}
2435
2437{
2438 if (!m_pOglThread->Active())
2439 return;
2440 if (!Pixmap)
2441 return;
2442
2444 int start = 1;
2445 if (m_isSubtitleOsd)
2446 start = 0;
2447 for (int i = start; i < m_pOglPixmaps.Size(); i++) {
2448 if (m_pOglPixmaps[i] == Pixmap) {
2449 if (Pixmap->Layer() >= 0)
2450 m_pOglPixmaps[0]->MarkViewPortDirty(m_pOglPixmaps[i]->ViewPort());
2451
2452 m_pOglPixmaps[i] = NULL;
2453 if (i)
2454 cOsd::DestroyPixmap(Pixmap);
2455
2456 return;
2457 }
2458 }
2459}
2460
2462{
2463 if (!m_pOglThread->Active() || !Active())
2464 return;
2465
2466 LOGDEBUG2(L_OSD, "openglosd: %s: Flush Osd %p", __FUNCTION__, this);
2468 // check for dirty areas
2469 m_pDirtyViewport.Set(0, 0, 0, 0);
2470 for (int i = 0; i < m_pOglPixmaps.Size(); i++) {
2471 if (m_pOglPixmaps[i] && m_pOglPixmaps[i]->IsDirty()) {
2472 if (m_isSubtitleOsd)
2473 m_pDirtyViewport.Combine(m_pOglPixmaps[i]->DirtyViewPort().Size());
2474 else
2476
2477 m_pOglPixmaps[i]->SetClean();
2478 }
2479 }
2480
2481 if (m_pDirtyViewport.IsEmpty())
2482 return;
2483
2484 // clear private buffer within the dirty area
2486 m_pDirtyViewport.X(),
2487 m_pDirtyViewport.Y(),
2488 m_pDirtyViewport.Width(),
2489 m_pDirtyViewport.Height(),
2491
2492 // render pixmap textures blended to private buffer
2493 for (int layer = 0; layer < MAXPIXMAPLAYERS; layer++) {
2494 for (int i = 0; i < m_pOglPixmaps.Size(); i++) {
2495 if (!m_pOglPixmaps[i])
2496 continue;
2497
2498 if (m_pOglPixmaps[i]->Layer () != layer)
2499 continue;
2500
2501 if (m_isSubtitleOsd && !m_pDirtyViewport.Intersects(m_pOglPixmaps[i]->ViewPort().Size()))
2502 continue;
2503
2504 if (!m_isSubtitleOsd && !m_pDirtyViewport.Intersects(m_pOglPixmaps[i]->ViewPort()))
2505 continue;
2506
2507 bool alphablending = layer == 0 ? false : true; // decide wether to render (with alpha) or copy a pixmap
2508 m_pOglThread->DoCmd(new cOglCmdRenderFbToBufferFb(m_pOglPixmaps[i]->Framebuffer(),
2510 m_isSubtitleOsd ? 0 : m_pOglPixmaps[i]->ViewPort().X(),
2511 m_isSubtitleOsd ? 0 : m_pOglPixmaps[i]->ViewPort().Y(),
2512 m_pOglPixmaps[i]->Alpha(),
2513 m_pOglPixmaps[i]->DrawPort().X(),
2514 m_pOglPixmaps[i]->DrawPort().Y(),
2515 m_pDirtyViewport.X(),
2516 m_pDirtyViewport.Top(),
2517 m_pDirtyViewport.Width(),
2518 m_pDirtyViewport.Height(),
2519 alphablending));
2520 }
2521 }
2522 // copy the private buffer to output framebuffer
2524
2526 Left() + (m_isSubtitleOsd ? m_pOglPixmaps[0]->ViewPort().X() : 0),
2527 Top() + (m_isSubtitleOsd ? m_pOglPixmaps[0]->ViewPort().Y() : 0), 1, m_pDevice));
2528}
2529
2530void cOglOsd::DrawScaledBitmap(int x, int y, const cBitmap &Bitmap, double FactorX, double FactorY, bool AntiAlias)
2531{
2532 if (!m_pOglPixmaps[0])
2533 return;
2534
2535 std::unique_ptr<cBitmap> scaledBitmap;
2536 const cBitmap *b = &Bitmap;
2537
2538 if (!DoubleEqual(FactorX, 1.0) || !DoubleEqual(FactorY, 1.0)) {
2539 scaledBitmap.reset(Bitmap.Scaled(FactorX, FactorY, AntiAlias));
2540 b = scaledBitmap.get();
2541 }
2542
2543 int xNew = x;
2544 int yNew = y;
2545
2546 const cRect &viewport = m_pOglPixmaps[0]->ViewPort();
2547 if (m_isSubtitleOsd && (x >= viewport.X()))
2548 xNew -= viewport.X();
2549 if (m_isSubtitleOsd && (y >= viewport.Y()))
2550 yNew -= viewport.Y();
2551
2552 m_pOglPixmaps[0]->DrawBitmap(cPoint(xNew, yNew), *b);
2553}
OpenGL OSD Glyph on a Texture Atlas.
Definition openglosd.h:146
OpenGL command: Fill a framebuffer.
Definition openglosd.h:485
virtual bool Execute(void)
OpenGL command: Render a framebuffer to the output framebuffer.
Definition openglosd.h:441
cOglOutputFb * m_pOutputFramebuffer
Definition openglosd.h:456
virtual bool Execute(void)
cSoftHdDevice * m_pDevice
Definition openglosd.h:460
OpenGL command: Delete a framebuffer.
Definition openglosd.h:390
virtual bool Execute(void)
OpenGL command: Draw an ellipse.
Definition openglosd.h:525
GLfloat * CreateVerticesFull(int &)
GLfloat * CreateVerticesHalf(int &)
GLfloat * CreateVerticesQuadrant(int &)
virtual bool Execute(void)
OpenGL command: Draw an image.
Definition openglosd.h:609
virtual bool Execute(void)
tColor * m_argb
Definition openglosd.h:626
OpenGL command: Draw a rectangle.
Definition openglosd.h:502
virtual bool Execute(void)
OpenGL command: Draw a slope.
Definition openglosd.h:554
virtual bool Execute(void)
OpenGL command: Draw a text.
Definition openglosd.h:579
cString m_fontName
Definition openglosd.h:599
unsigned int * m_pSymbols
Definition openglosd.h:601
virtual bool Execute(void)
OpenGL command: Draw a texture.
Definition openglosd.h:638
virtual bool Execute(void)
sOglImage * m_pImageRef
Definition openglosd.h:652
OpenGL command: Drop image from cache.
Definition openglosd.h:682
sOglImage * m_pImageRef
Definition openglosd.h:692
cCondWait * m_pWait
Definition openglosd.h:693
virtual bool Execute(void)
OpenGL command: Fill a polygon.
Definition openglosd.h:468
GLint m_color
Definition openglosd.h:477
virtual bool Execute(void)
OpenGL command: Init a framebuffer.
Definition openglosd.h:373
virtual bool Execute(void)
cCondWait * m_wait
Definition openglosd.h:382
OpenGL command: Init the output framebuffer.
Definition openglosd.h:356
cOglOutputFb * m_pOutputFramebuffer
Definition openglosd.h:365
virtual bool Execute(void)
OpenGL command: Render a framebuffer to another framebuffer.
Definition openglosd.h:404
virtual bool Execute(void)
OpenGL command: Store image in the cache.
Definition openglosd.h:663
sOglImage * m_pImageRef
Definition openglosd.h:673
virtual bool Execute(void)
OpenGL Hardware Command.
Definition openglosd.h:339
cOglFb * m_pFramebuffer
Definition openglosd.h:348
OpenGL OSD Framebuffer/ Texture Object.
Definition openglosd.h:238
GLint m_width
Definition openglosd.h:256
GLuint m_framebuffer
Definition openglosd.h:258
virtual void Unbind(void)
GLint ViewportHeight(void)
Definition openglosd.h:253
GLuint m_texture
Definition openglosd.h:259
void Bind(void)
GLint m_viewPortWidth
Definition openglosd.h:260
GLint Height(void)
Definition openglosd.h:250
cOglFb(GLint, GLint, GLint, GLint)
virtual ~cOglFb(void)
GLint ViewportWidth(void)
Definition openglosd.h:252
GLint Width(void)
Definition openglosd.h:249
bool m_scrollable
Definition openglosd.h:261
bool Scrollable(void)
Definition openglosd.h:251
GLint m_height
Definition openglosd.h:256
bool BindTexture(void)
GLint m_viewPortHeight
Definition openglosd.h:260
virtual bool Init(void)
bool m_initiated
Definition openglosd.h:255
OpenGL OSD Texture Atlas for a Font.
Definition openglosd.h:180
GLuint m_texture
Definition openglosd.h:189
cOglFontAtlas(FT_Face, int)
cOglAtlasGlyph * GetGlyph(int) const
virtual ~cOglFontAtlas(void)
void BindTexture(void)
cOglAtlasGlyph * m_pGlyph[MAX_CHARCODE - MIN_CHARCODE+1]
Definition openglosd.h:192
OpenGL OSD Representation of a VDR Font.
Definition openglosd.h:202
int Height(void)
Definition openglosd.h:211
int m_size
Definition openglosd.h:220
cString m_name
Definition openglosd.h:219
static void Cleanup(void)
cOglFont(const char *, int)
cOglFontAtlas * Atlas(void)
Definition openglosd.h:206
cOglGlyph * Glyph(FT_ULong) const
int Bottom(void)
Definition openglosd.h:210
static void Init(void)
static cOglFont * Get(const char *, int)
virtual ~cOglFont(void)
FT_Face m_face
Definition openglosd.h:223
cOglFontAtlas * m_pAtlas
Definition openglosd.h:225
int Kerning(cOglGlyph *glyph, FT_ULong prevSym) const
cList< cOglGlyph > m_glyphCache
Definition openglosd.h:224
int m_bottom
Definition openglosd.h:222
int m_height
Definition openglosd.h:221
static bool s_initiated
Definition openglosd.h:215
static FT_Library s_ftLib
Definition openglosd.h:216
static cList< cOglFont > * s_pFonts
Definition openglosd.h:217
OpenGL OSD Glyph of a Font.
Definition openglosd.h:103
void BindTexture(void)
GLuint m_texture
Definition openglosd.h:136
cOglGlyph(FT_ULong, FT_BitmapGlyph)
void LoadTexture(void)
unsigned char * m_pBuffer
Definition openglosd.h:133
void SetKerningCache(FT_ULong, int)
virtual ~cOglGlyph()
int GetKerningCache(FT_ULong)
int m_height
Definition openglosd.h:132
cVector< tKerning > m_pKerningCache
Definition openglosd.h:135
int m_width
Definition openglosd.h:131
virtual ~cOglOsd()
std::shared_ptr< cOglThread > m_pOglThread
pointer to thread, which executes the commands
Definition openglosd.h:825
bool m_isSubtitleOsd
true, if this is a subtitle osd
Definition openglosd.h:827
cSoftHdDevice * m_pDevice
pointer to cSofthdDevice
Definition openglosd.h:830
cOglFb * m_pBufferFramebuffer
all pixmaps are composed onto this framebuffer after each other, before this one is blit onto the OSD...
Definition openglosd.h:823
static cOglOutputFb * OutputFramebuffer
main OSD output framebuffer - this keeps our finished "OSD" (one per OSD)
Definition openglosd.h:821
virtual void Flush(void)
virtual eOsdError SetAreas(const tArea *, int)
cRect m_pDirtyViewport
the dirty viewport
Definition openglosd.h:829
virtual void DrawScaledBitmap(int, int, const cBitmap &, double, double, bool AntiAlias=false)
virtual cPixmap * CreatePixmap(int, const cRect &, const cRect &DrawPort=cRect::Null)
cVector< cOglPixmap * > m_pOglPixmaps
array of pixmaps
Definition openglosd.h:826
cOglOsd(int, int, uint, std::shared_ptr< cOglThread >, cSoftHdDevice *)
cSize m_maxPixmapSize
maximum allowed size of a pixmap (depends on the maximum OpenGL texture size)
Definition openglosd.h:828
virtual void DestroyPixmap(cPixmap *)
Main Framebuffer/ Texture Object for OSD.
Definition openglosd.h:271
GLuint m_framebuffer
Definition openglosd.h:278
virtual void Unbind(void)
GLuint m_texture
Definition openglosd.h:279
virtual bool Init(void)
OpenGL Implementation of a cPixmap.
Definition openglosd.h:758
virtual void Clear(void)
virtual void SetClean(void)
virtual void DrawRectangle(const cRect &, tColor)
virtual void Pan(const cPoint &, const cRect &Source=cRect::Null)
virtual void DrawPixel(const cPoint &, tColor)
void DrawTextInternal(const cPoint &, const char *, tColor, tColor, const cFont *, int Width=0, int Height=0, int Alignment=taDefault, bool isGridText=false)
virtual void DrawImage(const cPoint &, const cImage &)
virtual ~cOglPixmap(void)
cOglPixmap(std::shared_ptr< cOglThread >, int, const cRect &, const cRect &DrawPort=cRect::Null)
virtual void DrawSlope(const cRect &, tColor, int)
virtual void DrawText(const cPoint &, const char *, tColor, tColor, const cFont *, int Width=0, int Height=0, int Alignment=taDefault)
cOglFb * m_pFramebuffer
everything is drawn onto this framebuffer (one per pixmap)
Definition openglosd.h:792
std::shared_ptr< cOglThread > m_pOglThread
Definition openglosd.h:793
virtual void SetTile(bool)
virtual void SetDirty(bool dirty=true)
Definition openglosd.h:767
virtual void MarkViewPortDirty(const cRect &)
virtual void Scroll(const cPoint &, const cRect &Source=cRect::Null)
virtual void SetLayer(int)
virtual void Fill(tColor)
virtual void SetDrawPortPoint(const cPoint &, bool Dirty=true)
virtual void DrawBitmap(const cPoint &, const cBitmap &, tColor ColorFg=0, tColor ColorBg=0, bool Overlay=false)
virtual void Render(const cPixmap *, const cRect &, const cPoint &)
virtual void Copy(const cPixmap *, const cRect &, const cPoint &)
virtual void DrawEllipse(const cRect &, tColor, int Quadrants=0)
virtual void SetAlpha(int)
virtual void DrawScaledImage(const cPoint &, const cImage &, double FactorX=1.0f, double FactorY=1.0f, bool AntiAlias=false)
virtual void SetViewPort(const cRect &)
OpenGL OSD Vertex/Fragment Shader.
Definition openglosd.h:77
bool CheckCompileErrors(GLuint, bool program=false)
void SetMatrix4(const GLchar *, const glm::mat4 &)
void SetVector4f(const GLchar *, GLfloat, GLfloat, GLfloat, GLfloat)
void Use(void)
Definition openglosd.cpp:87
void SetFloat(const GLchar *, GLfloat)
void SetInteger(const GLchar *, GLint)
GLuint m_id
Definition openglosd.h:92
void SetVector3f(const GLchar *, GLfloat, GLfloat, GLfloat)
bool Load(eShaderType)
Definition openglosd.cpp:92
eShaderType m_type
Definition openglosd.h:91
bool Compile(const char *, const char *)
void SetVector2f(const GLchar *, GLfloat, GLfloat)
long m_memCached
Definition openglosd.h:736
void DoCmd(cOglCmd *)
long m_maxCacheSize
Definition openglosd.h:737
bool InitOpenGL(void)
bool InitVertexBuffers(void)
bool m_stalled
Definition openglosd.h:732
void CleanupImageCache(void)
sOglImage m_imageCache[OGL_MAX_OSDIMAGES]
Definition openglosd.h:735
int GetFreeSlot(void)
void Stop(void)
bool InitShaders(void)
cCondWait * m_startWait
Definition openglosd.h:730
cOglThread(cCondWait *startWait, int maxCacheSize, cSoftHdDevice *device)
cCondWait m_wait
Definition openglosd.h:731
void DropImageData(int)
void Cleanup(void)
void DeleteShaders(void)
virtual void Action(void)
void ClearSlot(int slot)
void RequestStop(void)
int StoreImage(const cImage &)
cVideoRender * m_pRender
Definition openglosd.h:738
sOglImage * GetImageRef(int)
std::mutex m_mutex
Definition openglosd.h:739
GLint m_maxTextureSize
Definition openglosd.h:734
void DeleteVertexBuffers(void)
std::queue< cOglCmd * > m_commands
Definition openglosd.h:733
void eglAcquireContext(void)
OpenGL OSD Vertex Buffers.
Definition openglosd.h:299
int m_sizeVertex2
Definition openglosd.h:326
GLuint m_positionLoc
Definition openglosd.h:323
void EnableBlending(void)
eVertexBufferType m_type
Definition openglosd.h:319
int m_sizeVertex1
Definition openglosd.h:325
int m_numVertices
Definition openglosd.h:327
eShaderType m_shader
Definition openglosd.h:320
void SetShaderColor(GLint)
GLuint m_texCoordsLoc
Definition openglosd.h:324
void SetShaderTexture(GLint)
void DisableBlending(void)
void SetVertexSubData(GLfloat *, int count=0)
void Bind(void)
void SetShaderProjectionMatrix(GLint, GLint)
void SetVertexData(GLfloat *, int count=0)
void DrawArrays(int count=0)
void ActivateShader(void)
GLuint m_vbo
Definition openglosd.h:322
void SetShaderAlpha(GLint)
bool Init(void)
void Unbind(void)
void SetShaderBorderColor(GLint)
GLuint m_drawMode
Definition openglosd.h:328
Output Device Implementation.
void OsdDrawARGB(int, int, int, int, int, const uint8_t *, int, int)
Draw an OSD pixmap.
virtual void GetOsdSize(int &, int &, double &)
Returns the width, height and aspect ratio the OSD.
void OsdClose(void)
Close the OSD.
EGLSurface EglSurface(void)
EGLDisplay EglDisplay(void)
EGLContext EglContext(void)
int GlInitiated(void)
__attribute__((weak)) union gbm_bo_handle gbm_bo_get_handle_for_plane(struct gbm_bo *bo
#define LOGDEBUG2
log to LOG_DEBUG and add a prefix
Definition logger.h:47
#define LOGERROR
log to LOG_ERR
Definition logger.h:39
#define GL_CHECK(stmt)
glCheckError macro
Definition misc.h:56
#define LOGWARNING
log to LOG_WARN
Definition logger.h:41
#define LOGINFO
log to LOG_INFO
Definition logger.h:43
#define EGL_CHECK(stmt)
eglCheckError macro
Definition misc.h:62
@ L_OPENGL_TIME
opengl osd flush time measurement
Definition logger.h:66
@ L_OSD
osd logs
Definition logger.h:59
@ L_OPENGL
opengl osd logs
Definition logger.h:65
@ L_OPENGL_TIME_ALL
opengl osd all commands time measurement
Definition logger.h:67
const char * textureFragmentShaderSwapBR
Texture Fragment Shader (swapped blue/red)
const char * rectVertexShader
Rectangle Vertex Shader.
static cOglVb * VertexBuffers[vbCount]
OpenGL Vertex Buffers Array.
Definition openglosd.cpp:82
const char * textureFragmentShader
Texture Fragment Shader.
const char * rectFragmentShader
Rectangle Fragment Shader.
const char * textFragmentShader
Text Fragment Shader.
static void ConvertColor(const GLint &colARGB, glm::vec4 &col)
OpenGL Color Conversion Helper.
Definition openglosd.cpp:63
const char * textureVertexShader
Texture Vertex Shader.
static cOglShader * Shaders[stCount]
OpenGL Shaders Array.
Definition openglosd.cpp:75
const char * textVertexShader
Text Vertex Shader.
Logger Header File.
Misc Functions.
#define KERNING_UNKNOWN
OpenGL OSD Header File.
#define OGL_MAX_OSDIMAGES
Definition openglosd.h:696
const char * message
Definition openglosd.h:34
#define MIN_CHARCODE
Definition openglosd.h:163
const struct @0 FT_Errors[]
int code
Definition openglosd.h:33
eShaderType
Definition openglosd.h:62
@ stText
Definition openglosd.h:66
@ stCount
Definition openglosd.h:67
@ stTextureSwapBR
Definition openglosd.h:65
@ stRect
Definition openglosd.h:63
@ stTexture
Definition openglosd.h:64
@ vbSlope
Definition openglosd.h:285
@ vbCount
Definition openglosd.h:289
@ vbText
Definition openglosd.h:288
@ vbTexture
Definition openglosd.h:286
@ vbEllipse
Definition openglosd.h:284
@ vbRect
Definition openglosd.h:283
@ vbTextureSwapBR
Definition openglosd.h:287
#define MAX_CHARCODE
Definition openglosd.h:164
#define OGL_CMDQUEUE_SIZE
Definition openglosd.h:697
Shader Definitions for OpenGL OSD.
Output Device Header File.
GLint height
Definition openglosd.h:58
bool used
Definition openglosd.h:59
GLint width
Definition openglosd.h:57
GLuint texture
Definition openglosd.h:56
Video Renderer (Display) Header File.