vdr-plugin-softhddevice-drm-gles 1.6.7
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 fontHeight = f->Height();
1386 int bottom = f->Bottom();
1387 FT_ULong sym = 0;
1388 FT_ULong prevSym = 0;
1389 int kerning = 0;
1390
1391 // Check, if we only have symbols, which are in our atlas
1392 int unknown_char = 0;
1393 for (int i = 0; m_pSymbols[i]; i++) {
1394 if ((m_pSymbols[i] < MIN_CHARCODE) || (m_pSymbols[i] > MAX_CHARCODE)) {
1395 if (m_pSymbols[i]) {
1397 break;
1398 }
1399 }
1400 }
1401
1402 if (!unknown_char) {
1403 cOglFontAtlas *fa = f->Atlas();
1404 std::vector<GLfloat> vertices;
1405 vertices.reserve( 4 * 6 * m_length);
1406
1407 for (int i = 0; m_pSymbols[i]; i++) {
1408 sym = m_pSymbols[i];
1409
1411 // Get the glyph from the font atlas for ASCII code MIN_CHARCODE-MAX_CHARCODE
1412 g = fa->GetGlyph(sym);
1413
1414 if (!g) {
1415 LOGWARNING("openglosd: %s: could not load glyph %lx", __FUNCTION__, sym);
1416 continue;
1417 }
1418
1419 if ( m_limitX && xGlyph + g->AdvanceX() > m_limitX )
1420 break;
1421
1422 kerning = f->Kerning(g, prevSym);
1423 prevSym = sym;
1424
1425 GLfloat x2 = xGlyph + kerning + g->BearingLeft();
1426 GLfloat y2 = m_y + (fontHeight - bottom - g->BearingTop()); //top
1427 GLfloat w = g->Width();
1428 GLfloat h = g->Height();
1429
1430 vertices.push_back(x2);
1431 vertices.push_back(y2);
1432 vertices.push_back(g->OffsetX());
1433 vertices.push_back(g->OffsetY());
1434
1435 vertices.push_back(x2 + w);
1436 vertices.push_back(y2);
1437 vertices.push_back(g->OffsetX() + g->Width() / (float)fa->Width());
1438 vertices.push_back(g->OffsetY());
1439
1440 vertices.push_back(x2);
1441 vertices.push_back(y2 + h);
1442 vertices.push_back(g->OffsetX());
1443 vertices.push_back(g->OffsetY() + g->Height() / (float)fa->Height());
1444
1445 vertices.push_back(x2 + w);
1446 vertices.push_back(y2);
1447 vertices.push_back(g->OffsetX() + g->Width() / (float)fa->Width());
1448 vertices.push_back(g->OffsetY());
1449
1450 vertices.push_back(x2);
1451 vertices.push_back(y2 + h);
1452 vertices.push_back(g->OffsetX());
1453 vertices.push_back(g->OffsetY() + g->Height() / (float)fa->Height());
1454
1455 vertices.push_back(x2 + w);
1456 vertices.push_back(y2 + h);
1457 vertices.push_back(g->OffsetX() + g->Width() / (float)fa->Width());
1458 vertices.push_back(g->OffsetY() + g->Height() / (float)fa->Height());
1459
1460 xGlyph += kerning + g->AdvanceX();
1461
1462 if ( xGlyph > m_pFramebuffer->Width() - 1 )
1463 break;
1464 }
1465
1466 fa->BindTexture();
1467 VertexBuffers[vbText]->SetVertexData(vertices.data(), (vertices.size() / 4));
1468 VertexBuffers[vbText]->DrawArrays(vertices.size() / 4);
1469 } else {
1470 LOGDEBUG2(L_OPENGL, "openglosd: %s: char %d is not on the texture atlas, use single draw", __FUNCTION__, unknown_char);
1471 for (int i = 0; m_pSymbols[i]; i++) {
1472 sym = m_pSymbols[i];
1473 cOglGlyph *g = f->Glyph(sym);
1474 if (!g) {
1475 LOGWARNING("openglosd: %s: could not load glyph %lx", __FUNCTION__, sym);
1476 continue;
1477 }
1478
1479 if ( m_limitX && xGlyph + g->AdvanceX() > m_limitX )
1480 break;
1481
1482 kerning = f->Kerning(g, prevSym);
1483 prevSym = sym;
1484
1485 GLfloat x1 = xGlyph + kerning + g->BearingLeft(); // left
1486 GLfloat y1 = m_y + (fontHeight - bottom - g->BearingTop()); // top
1487 GLfloat x2 = x1 + g->Width(); // right
1488 GLfloat y2 = y1 + g->Height(); // bottom
1489
1490 GLfloat vertices[] = {
1491 x1, y2, 0.0, 1.0, // left bottom
1492 x1, y1, 0.0, 0.0, // left top
1493 x2, y1, 1.0, 0.0, // right top
1494
1495 x1, y2, 0.0, 1.0, // left bottom
1496 x2, y1, 1.0, 0.0, // right top
1497 x2, y2, 1.0, 1.0 // right bottom
1498 };
1499
1500 g->BindTexture();
1501 VertexBuffers[vbText]->SetVertexData(vertices);
1502 VertexBuffers[vbText]->DrawArrays();
1503
1504 xGlyph += kerning + g->AdvanceX();
1505
1506 if ( xGlyph > m_pFramebuffer->Width() - 1 )
1507 break;
1508 }
1509 }
1510
1512 VertexBuffers[vbText]->Unbind();
1514 return true;
1515}
1516
1517//------------------ cOglCmdDrawImage -----------------------
1519{
1520 if (m_width <= 0 || m_height <= 0)
1521 return false;
1522
1523 GLuint texture;
1524 GL_CHECK(glGenTextures(1, &texture));
1528 0,
1529 GL_RGBA,
1530 m_width,
1531 m_height,
1532 0,
1533 GL_RGBA,
1535 m_argb
1536 ));
1542
1543 GLfloat x1 = m_x; // left
1544 GLfloat y1 = m_y; // top
1545 GLfloat x2 = m_x + m_width * m_scaleX; // right
1546 GLfloat y2 = m_y + m_height * m_scaleY; // bottom
1547
1548 GLfloat quadVertices[] = {
1549 x1, y2, 0.0, 1.0, // left bottom
1550 x1, y1, 0.0, 0.0, // left top
1551 x2, y1, 1.0, 0.0, // right top
1552
1553 x1, y2, 0.0, 1.0, // left bottom
1554 x2, y1, 1.0, 0.0, // right top
1555 x2, y2, 1.0, 1.0 // right bottom
1556 };
1557
1558 VertexBuffers[vbTextureSwapBR]->ActivateShader();
1559 VertexBuffers[vbTextureSwapBR]->SetShaderAlpha(255);
1560 VertexBuffers[vbTextureSwapBR]->SetShaderProjectionMatrix(m_pFramebuffer->Width(), m_pFramebuffer->Height());
1561 VertexBuffers[vbTextureSwapBR]->SetShaderBorderColor(m_borderColor);
1562
1565 if (m_overlay)
1566 VertexBuffers[vbTextureSwapBR]->DisableBlending();
1568 VertexBuffers[vbTextureSwapBR]->SetVertexSubData(quadVertices);
1569 VertexBuffers[vbTextureSwapBR]->DrawArrays();
1570 VertexBuffers[vbTextureSwapBR]->Unbind();
1571 if (m_overlay)
1572 VertexBuffers[vbTextureSwapBR]->EnableBlending();
1575 GL_CHECK(glDeleteTextures(1, &texture));
1576
1577 return true;
1578}
1579
1580//------------------ cOglCmdDrawTexture ---------------------
1582{
1583 if (m_pImageRef->width <= 0 || m_pImageRef->height <= 0)
1584 return false;
1585
1586 GLfloat x1 = m_x; // top
1587 GLfloat y1 = m_y; // left
1588 GLfloat x2 = m_x + m_pImageRef->width * m_scaleX; // right
1589 GLfloat y2 = m_y + m_pImageRef->height * m_scaleY; // bottom
1590
1591 GLfloat quadVertices[] = {
1592 // Pos // TexCoords
1593 x1, y1, 0.0f, 0.0f, // left bottom
1594 x1, y2, 0.0f, 1.0f, // left top
1595 x2, y2, 1.0f, 1.0f, // right top
1596
1597 x1, y1, 0.0f, 0.0f, // left bottom
1598 x2, y2, 1.0f, 1.0f, // right top
1599 x2, y1, 1.0f, 0.0f // right bottom
1600 };
1601
1602 VertexBuffers[vbTextureSwapBR]->ActivateShader();
1603 VertexBuffers[vbTextureSwapBR]->SetShaderAlpha(255);
1604 VertexBuffers[vbTextureSwapBR]->SetShaderProjectionMatrix(m_pFramebuffer->Width(), m_pFramebuffer->Height());
1605 VertexBuffers[vbTextureSwapBR]->SetShaderBorderColor(m_borderColor);
1606
1610 VertexBuffers[vbTextureSwapBR]->SetVertexSubData(quadVertices);
1611 VertexBuffers[vbTextureSwapBR]->DrawArrays();
1612 VertexBuffers[vbTextureSwapBR]->Unbind();
1614
1615 return true;
1616}
1617
1618//------------------ cOglCmdStoreImage ----------------------
1640
1641//------------------ cOglCmdDropImage -----------------------
1643 if (m_pImageRef->texture != GL_NONE)
1645 m_pWait->Signal();
1646 return true;
1647}
1648
1649/******************************************************************************
1650 * cOglThread
1651 *****************************************************************************/
1653 : cThread("oglThread"),
1654 m_startWait(startWait),
1655 m_maxCacheSize(maxCacheSize * 1024 * 1024),
1656 m_pRender(device->Render())
1657{
1658 for (int i = 0; i < OGL_MAX_OSDIMAGES; i++) {
1659 m_imageCache[i].used = false;
1661 m_imageCache[i].width = 0;
1662 m_imageCache[i].height = 0;
1663 }
1664
1665 Start();
1666}
1667
1669{
1670 for (int i = 0; i < OGL_MAX_OSDIMAGES; i++) {
1671 if (m_imageCache[i].used) {
1673 }
1674 }
1675}
1676
1678{
1680 Cancel(-1);
1681}
1682
1684{
1686 Cancel(2);
1687 Cleanup();
1688 m_stalled = false;
1689}
1690
1692{
1693 while (m_stalled)
1694 cCondWait::SleepMs(10);
1695
1696 bool doSignal = false;
1697 Lock();
1698 if (m_commands.size() == 0)
1699 doSignal = true;
1700 m_commands.push(cmd);
1701 Unlock();
1702
1703 if (m_commands.size() > OGL_CMDQUEUE_SIZE) {
1704 m_stalled = true;
1705 }
1706
1707 if (doSignal || m_stalled)
1708 m_wait.Signal();
1709}
1710
1712{
1713 if (!m_maxCacheSize) {
1714 LOGERROR("openglosd: %s: cannot store image, no cache set", __FUNCTION__);
1715 return 0;
1716 }
1717
1718 if (image.Width() > m_maxTextureSize || image.Height() > m_maxTextureSize) {
1719 LOGERROR("openglosd: %s: cannot store image of %dpx x %dpx (maximum size is %dpx x %dpx) - falling back to cOsdProvider::StoreImageData()",
1721 return 0;
1722 }
1723
1724 int imgSize = image.Width() * image.Height();
1725 int newMemUsed = imgSize * sizeof(tColor) + m_memCached;
1726 if (newMemUsed > m_maxCacheSize) {
1727 float cachedMB = m_memCached / 1024.0f / 1024.0f;
1728 float maxMB = m_maxCacheSize / 1024.0f / 1024.0f;
1729 LOGERROR("openglosd: %s: Maximum size for GPU cache reached. Used: %.2fMB Max: %.2fMB", __FUNCTION__, cachedMB, maxMB);
1730 return 0;
1731 }
1732
1733 int slot = GetFreeSlot();
1734 if (!slot)
1735 return 0;
1736
1738 if (!argb) {
1739 LOGERROR("openglosd: %s: memory allocation of %d kb for OSD image failed", __FUNCTION__, (int)(imgSize * sizeof(tColor) / 1024));
1740 ClearSlot(slot);
1741 slot = 0;
1742 return 0;
1743 }
1744
1745 memcpy(argb, image.Data(), sizeof(tColor) * imgSize);
1746
1748 imageRef->width = image.Width();
1749 imageRef->height = image.Height();
1751
1752 cTimeMs timer(5000);
1753 while (imageRef->used && imageRef->texture == 0 && !timer.TimedOut())
1754 cCondWait::SleepMs(2);
1755
1756 if (imageRef->texture == GL_NONE) {
1757 LOGERROR("openglosd: %s: failed to store OSD image texture! (%s)", __FUNCTION__, timer.TimedOut() ? "timed out" : "allocation failed");
1759 slot = 0;
1760 }
1761
1762 m_memCached += imgSize * sizeof(tColor);
1763
1764 return slot;
1765}
1766
1768{
1769 Lock();
1770 int slot = 0;
1771 for (int i = 0; i < OGL_MAX_OSDIMAGES && !slot; i++) {
1772 if (!m_imageCache[i].used) {
1773 m_imageCache[i].used = true;
1774 slot = -i - 1;
1775 }
1776 }
1777 Unlock();
1778 return slot;
1779}
1780
1782{
1783 int i = -slot - 1;
1784 if (i >= 0 && i < OGL_MAX_OSDIMAGES) {
1785 Lock();
1786 m_imageCache[i].used = false;
1788 m_imageCache[i].width = 0;
1789 m_imageCache[i].height = 0;
1790 Unlock();
1791 }
1792}
1793
1795{
1796 int i = -slot - 1;
1797 if (0 <= i && i < OGL_MAX_OSDIMAGES)
1798 return &m_imageCache[i];
1799 return 0;
1800}
1801
1803{
1805 if (!imageRef)
1806 return;
1807 int imgSize = imageRef->width * imageRef->height * sizeof(tColor);
1811 dropWait.Wait();
1813}
1814
1816{
1817 if (!InitOpenGL()) {
1818 LOGERROR("openglosd: %s: Could not initiate OpenGL context", __FUNCTION__);
1819 Cleanup();
1820 m_startWait->Signal();
1821 return;
1822 }
1823
1824 if (!InitShaders()) {
1825 LOGERROR("openglosd: %s: Could not initiate shaders", __FUNCTION__);
1826 Cleanup();
1827 m_startWait->Signal();
1828 return;
1829 }
1830
1831 if (!InitVertexBuffers()) {
1832 LOGERROR("openglosd: %s: Vertex Buffers NOT initialized", __FUNCTION__);
1833 Cleanup();
1834 m_startWait->Signal();
1835 return;
1836 }
1837
1839 LOGDEBUG2(L_OPENGL, "openglosd: %s: Maximum Pixmap size: %dx%dpx", __FUNCTION__, m_maxTextureSize, m_maxTextureSize);
1840
1841 //now Thread is ready to do his job
1842 m_startWait->Signal();
1843 m_stalled = false;
1844
1845 LOGINFO("OpenGL context initialized");
1846
1847 uint64_t startFlush = 0;
1848 uint64_t endFlush = 0;
1849 bool timeReset = false;
1850
1851 while(Running()) {
1852 if (m_commands.empty()) {
1853 m_wait.Wait(20);
1854 continue;
1855 }
1856
1857 Lock();
1858 cOglCmd* cmd = m_commands.front();
1859 m_commands.pop();
1860 Unlock();
1861
1862 uint64_t start = cTimeMs::Now();
1863 if (strcmp(cmd->Description(), "InitFramebuffer") == 0 || timeReset) {
1864 startFlush = cTimeMs::Now();
1865 timeReset = false;
1866 }
1867
1868 { // start of locked context
1869 std::unique_lock<std::mutex> lock(m_mutex, std::defer_lock);
1870
1871 if (cmd->NeedsLockingAgainstStateChange())
1872 lock.lock();
1873
1874 if (!Running())
1875 continue;
1876
1877 cmd->Execute();
1878 } // end of locked context
1879
1880 LOGDEBUG2(L_OPENGL_TIME_ALL, "openglosd: %s: \"%-*s\", %dms, %d commands left, time %" PRIu64 "",
1881 __FUNCTION__, 15, cmd->Description(), (int)(cTimeMs::Now() - start), (int)(m_commands.size()), cTimeMs::Now());
1882
1883 if (strcmp(cmd->Description(), "Copy buffer to OutputFramebuffer") == 0) {
1884 endFlush = cTimeMs::Now();
1885 timeReset = true;
1886 LOGDEBUG2(L_OPENGL_TIME, "openglosd: %s: OSD Flush %dms, time %" PRIu64 "", __FUNCTION__, (int)(endFlush - startFlush), cTimeMs::Now());
1887 }
1888 delete cmd;
1889 if (m_stalled && m_commands.size() < OGL_CMDQUEUE_SIZE / 2)
1890 m_stalled = false;
1891 }
1892
1893 LOGINFO("OpenGL worker thread stopped");
1894}
1895
1900
1906{
1907 LOGDEBUG2(L_OPENGL, "openglosd: %s: Init OpenGL context", __FUNCTION__);
1908
1909 // Wait for the EGL context to be created
1910 while(!m_pRender || !m_pRender->GlInitiated()) {
1911 LOGDEBUG2(L_OPENGL, "openglosd: %s: wait for EGL context", __FUNCTION__);
1912 usleep(20000);
1913 }
1914
1915 eglAcquireContext(); // eglMakeCurrent with new eglSurface
1916
1917 GL_CHECK(LOGDEBUG2(L_OPENGL, " GL Version: \"%s\"", glGetString(GL_VERSION)));
1918 GL_CHECK(LOGDEBUG2(L_OPENGL, " GL Vendor: \"%s\"", glGetString(GL_VENDOR)));
1919 GL_CHECK(LOGDEBUG2(L_OPENGL, " GL Extensions: \"%s\"", glGetString(GL_EXTENSIONS)));
1920 GL_CHECK(LOGDEBUG2(L_OPENGL, " GL Renderer: \"%s\"", glGetString(GL_RENDERER)));
1921
1922 VertexBuffers[vbText]->EnableBlending();
1924 LOGDEBUG2(L_OPENGL, "openglosd: %s: Init OpenGL context done", __FUNCTION__);
1925
1926 return true;
1927}
1928
1930{
1931 for (int i = 0; i < stCount; i++) {
1932 cOglShader *shader = new cOglShader();
1933 if (!shader->Load((eShaderType)i))
1934 return false;
1935 Shaders[i] = shader;
1936 }
1937 LOGDEBUG2(L_OPENGL, "openglosd: %s: Shaders initialized", __FUNCTION__);
1938
1939 return true;
1940}
1941
1943{
1944 for (int i = 0; i < stCount; i++)
1945 delete Shaders[i];
1946}
1947
1949{
1950 for (int i = 0; i < vbCount; i++) {
1951 cOglVb *vb = new cOglVb(i);
1952 if (!vb->Init())
1953 return false;
1954 VertexBuffers[i] = vb;
1955 }
1956 LOGDEBUG2(L_OPENGL, "openglosd: %s: Vertex buffers initialized", __FUNCTION__);
1957
1958 return true;
1959}
1960
1962{
1963 for (int i=0; i < vbCount; i++) {
1964 delete VertexBuffers[i];
1965 }
1966}
1967
1969{
1970 LOGDEBUG2(L_OPENGL, "openglosd: %s: Cleaning up OpenGL stuff", __FUNCTION__);
1971
1975 DeleteShaders();
1977}
1978
1979/******************************************************************************
1980 * cOglPixmap
1981 *****************************************************************************/
1982cOglPixmap::cOglPixmap(std::shared_ptr<cOglThread> oglThread, int layer, const cRect &viewPort, const cRect &drawPort)
1983 : cPixmap(layer, viewPort, drawPort),
1984 m_pOglThread(oglThread)
1985{
1986 int width = drawPort.IsEmpty() ? viewPort.Width() : drawPort.Width();
1987 int height = drawPort.IsEmpty() ? viewPort.Height() : drawPort.Height();
1988
1989 if (width > m_pOglThread->MaxTextureSize() || height > m_pOglThread->MaxTextureSize()) {
1990 LOGWARNING("openglosd: %s: cannot allocate pixmap of %dpx x %dpx, clipped to %dpx x %dpx!", __FUNCTION__,
1991 width, height, std::min(width, m_pOglThread->MaxTextureSize()), std::min(height, m_pOglThread->MaxTextureSize()));
1992 width = std::min(width, m_pOglThread->MaxTextureSize());
1993 height = std::min(height, m_pOglThread->MaxTextureSize());
1994 }
1995
1996 m_pFramebuffer = new cOglFb(width, height, viewPort.Width(), viewPort.Height());
1997
1998#ifdef GRIDPOINTS
1999 // Creates a tiny font with height GRIDPOINTSTXTSIZE
2000 m_pTinyfont = cFont::CreateFont(Setup.FontOsd, GRIDPOINTSTXTSIZE);
2001#endif
2002}
2003
2005{
2006 if (!m_pOglThread->Active())
2007 return;
2008
2010#ifdef GRIDPOINTS
2011 delete m_pTinyfont;
2012#endif
2013}
2014
2016{
2017 cPixmap::MarkViewPortDirty(rect);
2018 SetDirty();
2019}
2020
2022{
2023 cPixmap::SetClean();
2024 SetDirty(false);
2025}
2026
2028{
2029 cPixmap::SetLayer(layer);
2030 SetDirty();
2031}
2032
2034{
2036 if (alpha != cPixmap::Alpha()) {
2037 cPixmap::SetAlpha(alpha);
2038 SetDirty();
2039 }
2040}
2041
2043{
2044 cPixmap::SetTile(tile);
2045 SetDirty();
2046}
2047
2049{
2050 cPixmap::SetViewPort(rect);
2051 SetDirty();
2052}
2053
2055{
2056 cPixmap::SetDrawPortPoint(point, dirty);
2057 if (dirty)
2058 SetDirty();
2059}
2060
2062{
2063 if (!m_pOglThread->Active())
2064 return;
2065
2068 SetDirty();
2070}
2071
2073{
2074 if (!m_pOglThread->Active())
2075 return;
2076
2079 SetDirty();
2081}
2082
2084{
2086}
2087
2092
2093void cOglPixmap::DrawScaledImage(const cPoint &point, const cImage &image, double factorX, double factorY, __attribute__ ((unused)) bool antiAlias)
2094{
2095 if (!m_pOglThread->Active())
2096 return;
2097
2098 tColor *argb = MALLOC(tColor, image.Width() * image.Height());
2099 if (!argb)
2100 return;
2101 memcpy(argb, image.Data(), sizeof(tColor) * image.Width() * image.Height());
2102
2103 m_pOglThread->DoCmd(new cOglCmdDrawImage(m_pFramebuffer, argb, image.Width(), image.Height(), point.X(), point.Y(), true, factorX, factorY));
2104#ifdef GRIDRECT
2106#endif
2107 SetDirty();
2108 MarkDrawPortDirty(cRect(point, cSize(image.Width() * factorX, image.Height() * factorY)).Intersected(DrawPort().Size()));
2109}
2110
2112{
2113 if (!m_pOglThread->Active())
2114 return;
2115
2117 sOglImage *img = m_pOglThread->GetImageRef(imageHandle);
2119#ifdef GRIDRECT
2121#endif
2122 SetDirty();
2123 MarkDrawPortDirty(cRect(point, cSize(img->width * factorX, img->height * factorY)).Intersected(DrawPort().Size()));
2124 }
2125}
2126
2128{
2129 cRect r(point.X(), point.Y(), 1, 1);
2130 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, r.X(), r.Y(), r.Width(), r.Height(), color));
2131#ifdef GRIDRECT
2133#endif
2134 SetDirty();
2136}
2137
2139{
2140 if (!m_pOglThread->Active())
2141 return;
2142
2144 bool specialColors = colorFg || colorBg;
2145 tColor *argb = MALLOC(tColor, bitmap.Width() * bitmap.Height());
2146 if (!argb)
2147 return;
2148
2149 tColor *p = argb;
2150 for (int py = 0; py < bitmap.Height(); py++)
2151 for (int px = 0; px < bitmap.Width(); px++) {
2152 tIndex index = *bitmap.Data(px, py);
2153 *p++ = (!index && overlay) ? clrTransparent :
2154 (specialColors ? (index == 0 ? colorBg : index == 1 ? colorFg :
2155 bitmap.Color(index)) : bitmap.Color(index));
2156 }
2157
2158 m_pOglThread->DoCmd(new cOglCmdDrawImage(m_pFramebuffer, argb, bitmap.Width(), bitmap.Height(), point.X(), point.Y(), true));
2159#ifdef GRIDRECT
2161#endif
2162
2163 SetDirty();
2164 MarkDrawPortDirty(cRect(cPoint(point.X(), point.Y()), cSize(bitmap.Width(), bitmap.Height())).Intersected(DrawPort().Size()));
2165}
2166
2167void cOglPixmap::DrawText(const cPoint &point, const char *s, tColor colorFg, tColor colorBg, const cFont *font, int width, int height, int alignment)
2168{
2169 DrawTextInternal(point, s, colorFg, colorBg, font, width, height, alignment, false);
2170}
2171
2172#ifdef GRIDPOINTS
2173void cOglPixmap::DrawGridText(const cPoint &point, const char *s, tColor colorFg, tColor colorBg, const cFont *font, int width, int height, int alignment)
2174{
2175 DrawTextInternal(point, s, colorFg, colorBg, font, width, height, alignment, true);
2176}
2177#endif
2178
2179void cOglPixmap::DrawTextInternal(const cPoint &point, const char *s, tColor colorFg, tColor colorBg, const cFont *font, int width, int height, int alignment, bool isGridText)
2180{
2181 if (!m_pOglThread->Active())
2182 return;
2183
2185 int len = s ? Utf8StrLen(s) : 0;
2186 unsigned int *symbols = MALLOC(unsigned int, len + 1);
2187 if (!symbols)
2188 return;
2189
2190 if (len)
2191 Utf8ToArray(s, symbols, len + 1);
2192 else
2193 symbols[0] = 0;
2194
2195 int x = point.X();
2196 int y = point.Y();
2197 int w = font->Width(s);
2198 int h = font->Height();
2199 int limitX = 0;
2200 int cw = width ? width : w;
2201 int ch = height ? height : h;
2202
2203 // workaround for messages in SkinElchiHD
2204 if (width > ViewPort().Width() && !x && !isGridText)
2205 x = ViewPort().Width() - w;
2206
2207 cRect r(x, y, cw, ch);
2208
2209 if (colorBg != clrTransparent)
2210 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, r.X(), r.Y(), r.Width(), r.Height(), colorBg));
2211
2212 if (width || height)
2213 limitX = x + cw;
2214
2215 if (width) {
2216 if ((alignment & taLeft) != 0) {
2217 if ((alignment & taBorder) != 0)
2218 x += std::max(h / TEXT_ALIGN_BORDER, 1);
2219 } else if ((alignment & taRight) != 0) {
2220 if (w < width)
2221 x += width - w;
2222 if ((alignment & taBorder) != 0)
2223 x -= std::max(h / TEXT_ALIGN_BORDER, 1);
2224 } else { // taCentered
2225 if (w < width)
2226 x += (width - w) / 2;
2227 }
2228 }
2229
2230 if (height) {
2231 if ((alignment & taTop) != 0)
2232 ;
2233 else if ((alignment & taBottom) != 0) {
2234 if (h < height)
2235 y += height - h;
2236 } else { // taCentered
2237 if (h < height)
2238 y += (height - h) / 2;
2239 }
2240 }
2241
2242 m_pOglThread->DoCmd(new cOglCmdDrawText(m_pFramebuffer, x, y, symbols, limitX, font->FontName(), font->Size(), colorFg, len));
2243
2244#ifdef GRIDTEXT
2245 if (!isGridText)
2247#endif
2248
2249 SetDirty();
2251}
2252
2254{
2255 if (!m_pOglThread->Active())
2256 return;
2257
2259 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, rect.X(), rect.Y(), rect.Width(), rect.Height(), color));
2260#ifdef GRIDRECT
2262#endif
2263
2264 SetDirty();
2266}
2267
2269{
2270 if (!m_pOglThread->Active())
2271 return;
2272
2274 m_pOglThread->DoCmd(new cOglCmdDrawEllipse(m_pFramebuffer, rect.X(), rect.Y(), rect.Width(), rect.Height(), color, quadrants));
2275#ifdef GRIDRECT
2277#endif
2278
2279 SetDirty();
2281}
2282
2284{
2285 if (!m_pOglThread->Active())
2286 return;
2287
2289 m_pOglThread->DoCmd(new cOglCmdDrawSlope(m_pFramebuffer, rect.X(), rect.Y(), rect.Width(), rect.Height(), color, type));
2290#ifdef GRIDRECT
2292#endif
2293
2294 SetDirty();
2296}
2297
2298void cOglPixmap::Render(const cPixmap *pixmap, const cRect &source, const cPoint &dest)
2299{
2300 LOGWARNING("openglosd: %s: %d %d %d not implemented in OpenGl OSD", __FUNCTION__, pixmap->ViewPort().X(), source.X(), dest.X());
2301}
2302
2303void cOglPixmap::Copy(const cPixmap *pixmap, const cRect &source, const cPoint &dest)
2304{
2305 LOGWARNING("openglosd: %s: %d %d %d not implemented in OpenGl OSD", __FUNCTION__, pixmap->ViewPort().X(), source.X(), dest.X());
2306}
2307
2309{
2310 LOGWARNING("openglosd: %s: %d %d not implemented in OpenGl OSD", __FUNCTION__, source.X(), dest.X());
2311}
2312
2314{
2315 LOGWARNING("openglosd: %s: %d %d not implemented in OpenGl OSD", __FUNCTION__, source.X(), dest.X());
2316}
2317
2318#ifdef GRIDPOINTS
2319void cOglPixmap::DrawGridRect(const cRect &rect, int offset, int size, tColor clr, tColor bg, const cFont *font)
2320{
2321 int x1 = rect.X() + offset;
2322 int x2 = rect.X() + rect.Width() + offset;
2323 int y1 = rect.Y();
2324 int y2 = rect.Y() + rect.Height();
2325 char p1[10];
2326 char p2[10];
2327 char p3[10];
2328 char p4[10];
2329 sprintf(p1, "%d.%d", x1, y1);
2330 sprintf(p2, "%d.%d", x2, y1);
2331 sprintf(p3, "%d.%d", x1, y2);
2332 sprintf(p4, "%d.%d", x2, y2);
2333
2334 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, x1, y1, size, size, clr));
2335#ifdef GRIDPOINTSTEXT
2337#endif
2338 if (Rect.Width() && Rect.Height()) {
2339 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, x2, y1, size, size, clr));
2340 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, x1, y2, size, size, clr));
2341 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, x2, y2, size, size, clr));
2342#ifdef GRIDPOINTSTEXT
2346#endif
2347 }
2348}
2349#endif
2350
2351/******************************************************************************
2352 * cOglOsd
2353 *****************************************************************************/
2355
2356cOglOsd::cOglOsd(int left, int top, uint level, std::shared_ptr<cOglThread> oglThread, cSoftHdDevice *device)
2357 : cOsd(left, top, level),
2358 m_pOglThread(oglThread),
2359 m_isSubtitleOsd(level == 10 ? true : false),
2360 m_pDevice(device)
2361{
2362 int osdWidth = 0;
2363 int osdHeight = 0;
2364 double pixelAspect;
2366 LOGDEBUG2(L_OSD, "openglosd: %s: New Osd %p osdLeft %d osdTop %d screenWidth %d screenHeight %d", __FUNCTION__, this, left, top, osdWidth, osdHeight);
2367
2368 m_maxPixmapSize.Set(m_pOglThread->MaxTextureSize(), m_pOglThread->MaxTextureSize());
2369
2370 if (!OutputFramebuffer) {
2373 }
2374}
2375
2377{
2378 if (!m_pOglThread->Active() || !Active() || !m_pBufferFramebuffer)
2379 return;
2380
2381 LOGDEBUG2(L_OSD, "openglosd: %s: Delete Osd %p", __FUNCTION__, this);
2383
2384 SetActive(false); // OsdClose() is done in cOglCmdCopyBufferToOutputFb()
2387}
2388
2390{
2391 cRect r;
2392 if (numAreas > 1)
2393 m_isSubtitleOsd = true;
2394 for (int i = 0; i < numAreas; i++)
2395 r.Combine(cRect(areas[i].x1, areas[i].y1, areas[i].Width(), areas[i].Height()));
2396
2397 tArea area = { r.Left(), r.Top(), r.Right(), r.Bottom(), 32 };
2398
2399 // now we know the actual osd size, create double buffer frame buffer
2403 }
2404 m_pBufferFramebuffer = new cOglFb(r.Width(), r.Height(), r.Width(), r.Height());
2407 initiated.Wait();
2408
2409 return cOsd::SetAreas(&area, 1);
2410}
2411
2413{
2414 if (!m_pOglThread->Active())
2415 return NULL;
2416
2419 if (cOsd::AddPixmap(p)) {
2420 // find a free slot
2421 for (int i = 0; i < m_pOglPixmaps.Size(); i++) {
2422 if (!m_pOglPixmaps[i])
2423 return m_pOglPixmaps[i] = p;
2424 }
2425 m_pOglPixmaps.Append(p);
2426 return p;
2427 }
2428 delete p;
2429
2430 return NULL;
2431}
2432
2434{
2435 if (!m_pOglThread->Active())
2436 return;
2437 if (!Pixmap)
2438 return;
2439
2441 int start = 1;
2442 if (m_isSubtitleOsd)
2443 start = 0;
2444 for (int i = start; i < m_pOglPixmaps.Size(); i++) {
2445 if (m_pOglPixmaps[i] == Pixmap) {
2446 if (Pixmap->Layer() >= 0)
2447 m_pOglPixmaps[0]->MarkViewPortDirty(m_pOglPixmaps[i]->ViewPort());
2448
2449 m_pOglPixmaps[i] = NULL;
2450 if (i)
2451 cOsd::DestroyPixmap(Pixmap);
2452
2453 return;
2454 }
2455 }
2456}
2457
2459{
2460 if (!m_pOglThread->Active() || !Active())
2461 return;
2462
2463 LOGDEBUG2(L_OSD, "openglosd: %s: Flush Osd %p", __FUNCTION__, this);
2465 // check for dirty areas
2466 m_pDirtyViewport.Set(0, 0, 0, 0);
2467 for (int i = 0; i < m_pOglPixmaps.Size(); i++) {
2468 if (m_pOglPixmaps[i] && m_pOglPixmaps[i]->IsDirty()) {
2469 if (m_isSubtitleOsd)
2470 m_pDirtyViewport.Combine(m_pOglPixmaps[i]->DirtyViewPort().Size());
2471 else
2473
2474 m_pOglPixmaps[i]->SetClean();
2475 }
2476 }
2477
2478 if (m_pDirtyViewport.IsEmpty())
2479 return;
2480
2481 // clear private buffer within the dirty area
2483 m_pDirtyViewport.X(),
2484 m_pDirtyViewport.Y(),
2485 m_pDirtyViewport.Width(),
2486 m_pDirtyViewport.Height(),
2488
2489 // render pixmap textures blended to private buffer
2490 for (int layer = 0; layer < MAXPIXMAPLAYERS; layer++) {
2491 for (int i = 0; i < m_pOglPixmaps.Size(); i++) {
2492 if (!m_pOglPixmaps[i])
2493 continue;
2494
2495 if (m_pOglPixmaps[i]->Layer () != layer)
2496 continue;
2497
2498 if (m_isSubtitleOsd && !m_pDirtyViewport.Intersects(m_pOglPixmaps[i]->ViewPort().Size()))
2499 continue;
2500
2501 if (!m_isSubtitleOsd && !m_pDirtyViewport.Intersects(m_pOglPixmaps[i]->ViewPort()))
2502 continue;
2503
2504 bool alphablending = layer == 0 ? false : true; // decide wether to render (with alpha) or copy a pixmap
2505 m_pOglThread->DoCmd(new cOglCmdRenderFbToBufferFb(m_pOglPixmaps[i]->Framebuffer(),
2507 m_isSubtitleOsd ? 0 : m_pOglPixmaps[i]->ViewPort().X(),
2508 m_isSubtitleOsd ? 0 : m_pOglPixmaps[i]->ViewPort().Y(),
2509 m_pOglPixmaps[i]->Alpha(),
2510 m_pOglPixmaps[i]->DrawPort().X(),
2511 m_pOglPixmaps[i]->DrawPort().Y(),
2512 m_pDirtyViewport.X(),
2513 m_pDirtyViewport.Top(),
2514 m_pDirtyViewport.Width(),
2515 m_pDirtyViewport.Height(),
2516 alphablending));
2517 }
2518 }
2519 // copy the private buffer to output framebuffer
2521
2523 Left() + (m_isSubtitleOsd ? m_pOglPixmaps[0]->ViewPort().X() : 0),
2524 Top() + (m_isSubtitleOsd ? m_pOglPixmaps[0]->ViewPort().Y() : 0), 1, m_pDevice));
2525}
2526
2527void cOglOsd::DrawScaledBitmap(int x, int y, const cBitmap &Bitmap, double FactorX, double FactorY, bool AntiAlias)
2528{
2529 if (!m_pOglPixmaps[0])
2530 return;
2531
2532 std::unique_ptr<cBitmap> scaledBitmap;
2533 const cBitmap *b = &Bitmap;
2534
2535 if (!DoubleEqual(FactorX, 1.0) || !DoubleEqual(FactorY, 1.0)) {
2536 scaledBitmap.reset(Bitmap.Scaled(FactorX, FactorY, AntiAlias));
2537 b = scaledBitmap.get();
2538 }
2539
2540 int xNew = x;
2541 int yNew = y;
2542
2543 const cRect &viewport = m_pOglPixmaps[0]->ViewPort();
2544 if (m_isSubtitleOsd && (x >= viewport.X()))
2545 xNew -= viewport.X();
2546 if (m_isSubtitleOsd && (y >= viewport.Y()))
2547 yNew -= viewport.Y();
2548
2549 m_pOglPixmaps[0]->DrawBitmap(cPoint(xNew, yNew), *b);
2550}
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 should have.
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.