vdr-plugin-softhddevice-drm-gles 1.6.8-daba64b
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//------------------ cOglCmdRenderFbToFb ------------------------
1033 if (!m_pFramebuffer || !m_pSrcFb || m_srcRect.IsEmpty() || m_pFramebuffer == m_pSrcFb)
1034 return false;
1035
1036 GLfloat x1 = m_dstPoint.X();
1037 GLfloat y1 = m_dstPoint.Y();
1038 GLfloat x2 = x1 + m_srcRect.Width();
1039 GLfloat y2 = y1 + m_srcRect.Height();
1040
1042 GLfloat texX2 = (GLfloat)(m_srcRect.X() + m_srcRect.Width()) / (GLfloat)m_pSrcFb->Width();
1044 GLfloat texY2 = (GLfloat)(m_pSrcFb->Height() - m_srcRect.Y() - m_srcRect.Height() - 1) / (GLfloat)m_pSrcFb->Height();
1045
1046 GLfloat quadVertices[] = {
1047 // Position Texture
1048 x1, y1, texX1, texY2,
1049 x1, y2, texX1, texY1,
1050 x2, y2, texX2, texY1,
1051
1052 x1, y1, texX1, texY2,
1053 x2, y2, texX2, texY1,
1054 x2, y1, texX2, texY2
1055 };
1056
1057 VertexBuffers[vbTexture]->ActivateShader();
1058 VertexBuffers[vbTexture]->SetShaderAlpha(m_alpha);
1059 VertexBuffers[vbTexture]->SetShaderProjectionMatrix(m_pFramebuffer->Width(), m_pFramebuffer->Height());
1060 VertexBuffers[vbTexture]->SetShaderBorderColor(clrTransparent);
1061
1063
1064 if (!m_pSrcFb->BindTexture()) {
1066 return false;
1067 }
1068
1069 if (m_alpha == ALPHA_OPAQUE)
1070 VertexBuffers[vbTexture]->DisableBlending();
1071
1072 VertexBuffers[vbTexture]->Bind();
1073 VertexBuffers[vbTexture]->SetVertexSubData(quadVertices);
1074 VertexBuffers[vbTexture]->DrawArrays();
1075 VertexBuffers[vbTexture]->Unbind();
1076
1077 if (m_alpha == ALPHA_OPAQUE)
1078 VertexBuffers[vbTexture]->EnableBlending();
1079
1081
1082 return true;
1083}
1084
1085//------------------ cOglCmdFill ----------------------------
1087{
1088 glm::vec4 col;
1091 GL_CHECK(glClearColor(col.r, col.g, col.b, col.a));
1094
1095 return true;
1096}
1097
1098//------------------ cOglCmdBufferFill ----------------------
1100{
1101 glm::vec4 col;
1103 GL_CHECK(glClearColor(col.r, col.g, col.b, col.a));
1105
1106 return true;
1107}
1108
1109//------------------ cOglCmdDrawRectangle -------------------
1111{
1112 if (m_width <= 0 || m_height <= 0)
1113 return false;
1114
1115 GLfloat x1 = m_x;
1116 GLfloat y1 = m_y;
1117 GLfloat x2 = m_x + m_width;
1118 GLfloat y2 = m_y + m_height;
1119
1120 GLfloat vertices[] = {
1121 x1, y1, // left top
1122 x2, y1, // right top
1123 x2, y2, // right bottom
1124 x1, y2 // left bottom
1125 };
1126
1127 VertexBuffers[vbRect]->ActivateShader();
1128 VertexBuffers[vbRect]->SetShaderColor(m_color);
1129 VertexBuffers[vbRect]->SetShaderProjectionMatrix(m_pFramebuffer->Width(), m_pFramebuffer->Height());
1130
1132 VertexBuffers[vbRect]->DisableBlending();
1133 VertexBuffers[vbRect]->Bind();
1134 VertexBuffers[vbRect]->SetVertexSubData(vertices);
1135 VertexBuffers[vbRect]->DrawArrays();
1136 VertexBuffers[vbRect]->Unbind();
1137 VertexBuffers[vbRect]->EnableBlending();
1139
1140 return true;
1141}
1142
1143//------------------ cOglCmdDrawEllipse ---------------------
1144// quadrants:
1145// 0 draws the entire ellipse
1146// 1..4 draws only the first, second, third or fourth quadrant, respectively
1147// 5..8 draws the right, top, left or bottom half, respectively
1148// -1..-4 draws the inverted part of the given quadrant
1149//-----------------------------------------------------------
1151{
1152 if (m_width <= 0 || m_height <= 0)
1153 return false;
1154
1155 int numVertices = 0;
1157
1158 switch (m_quadrants) {
1159 case 0:
1161 break;
1162 case 1:
1163 case 2:
1164 case 3:
1165 case 4:
1166 case -1:
1167 case -2:
1168 case -3:
1169 case -4:
1171 break;
1172 case 5:
1173 case 6:
1174 case 7:
1175 case 8:
1177 break;
1178 default:
1179 break;
1180 }
1181
1182 VertexBuffers[vbEllipse]->ActivateShader();
1183 VertexBuffers[vbEllipse]->SetShaderColor(m_color);
1184 VertexBuffers[vbEllipse]->SetShaderProjectionMatrix(m_pFramebuffer->Width(), m_pFramebuffer->Height());
1185
1186 // not antialiased
1188 VertexBuffers[vbEllipse]->DisableBlending();
1189 VertexBuffers[vbEllipse]->Bind();
1190 VertexBuffers[vbEllipse]->SetVertexSubData(vertices, numVertices);
1191 VertexBuffers[vbEllipse]->DrawArrays(numVertices);
1192 VertexBuffers[vbEllipse]->Unbind();
1193 VertexBuffers[vbEllipse]->EnableBlending();
1195
1196 delete[] vertices;
1197 return true;
1198}
1199
1201{
1202 int size = 364;
1203 numVertices = size/2;
1206 GLfloat *vertices = new GLfloat[size];
1207 vertices[0] = m_x + radiusX;
1208 vertices[1] = m_y + radiusY;
1209 for (int i=0; i <= 180; i++) {
1210 vertices[2 * i + 2] = m_x + radiusX + (GLfloat)cos(2 * i * M_PI / 180.0f) * radiusX;
1211 vertices[2 * i + 3] = m_y + radiusY - (GLfloat)sin(2 * i * M_PI / 180.0f) * radiusY;
1212 }
1213 return vertices;
1214}
1215
1217{
1218 int size = 94;
1219 numVertices = size / 2;
1222 GLint transX = 0;
1223 GLint transY = 0;
1224 GLint startAngle = 0;
1225 GLfloat *vertices = new GLfloat[size];
1226 switch (m_quadrants) {
1227 case 1:
1228 vertices[0] = m_x;
1229 vertices[1] = m_y + m_height;
1230 transY = radiusY;
1231 break;
1232 case 2:
1233 vertices[0] = m_x + m_width;
1234 vertices[1] = m_y + m_height;
1235 transX = radiusX;
1236 transY = radiusY;
1237 startAngle = 90;
1238 break;
1239 case 3:
1240 vertices[0] = m_x + m_width;
1241 vertices[1] = m_y;
1242 transX = radiusX;
1243 startAngle = 180;
1244 break;
1245 case 4:
1246 vertices[0] = m_x;
1247 vertices[1] = m_y;
1248 startAngle = 270;
1249 break;
1250 case -1:
1251 vertices[0] = m_x + m_width;
1252 vertices[1] = m_y;
1253 transY = radiusY;
1254 break;
1255 case -2:
1256 vertices[0] = m_x;
1257 vertices[1] = m_y;
1258 transX = radiusX;
1259 transY = radiusY;
1260 startAngle = 90;
1261 break;
1262 case -3:
1263 vertices[0] = m_x;
1264 vertices[1] = m_y + m_height;
1265 transX = radiusX;
1266 startAngle = 180;
1267 break;
1268 case -4:
1269 vertices[0] = m_x + m_width;
1270 vertices[1] = m_y + m_height;
1271 startAngle = 270;
1272 break;
1273 default:
1274 break;
1275 }
1276 for (int i = 0; i <= 45; i++) {
1277 vertices[2 * i + 2] = m_x + transX + (GLfloat)cos((2 * i + startAngle) * M_PI / 180.0f) * radiusX;
1278 vertices[2 * i + 3] = m_y + transY - (GLfloat)sin((2 * i + startAngle) * M_PI / 180.0f) * radiusY;
1279 }
1280 return vertices;
1281}
1282
1284{
1285 int size = 184;
1286 numVertices = size / 2;
1287 GLfloat radiusX = 0.0f;
1288 GLfloat radiusY = 0.0f;
1289 GLint transX = 0;
1290 GLint transY = 0;
1291 GLint startAngle = 0;
1292 GLfloat *vertices = new GLfloat[size];
1293 switch (m_quadrants) {
1294 case 5:
1296 radiusY = (GLfloat)m_height / 2;
1297 vertices[0] = m_x;
1298 vertices[1] = m_y + radiusY;
1299 startAngle = 270;
1300 transY = radiusY;
1301 break;
1302 case 6:
1303 radiusX = (GLfloat)m_width / 2;
1305 vertices[0] = m_x + radiusX;
1306 vertices[1] = m_y + radiusY;
1307 startAngle = 0;
1308 transX = radiusX;
1309 transY = radiusY;
1310 break;
1311 case 7:
1313 radiusY = (GLfloat)m_height / 2;
1314 vertices[0] = m_x + radiusX;
1315 vertices[1] = m_y + radiusY;
1316 startAngle = 90;
1317 transX = radiusX;
1318 transY = radiusY;
1319 break;
1320 case 8:
1321 radiusX = (GLfloat)m_width / 2;
1323 vertices[0] = m_x + radiusX;
1324 vertices[1] = m_y;
1325 startAngle = 180;
1326 transX = radiusX;
1327 break;
1328 default:
1329 break;
1330 }
1331 for (int i=0; i <= 90; i++) {
1332 vertices[2 * i + 2] = m_x + transX + (GLfloat)cos((2 * i + startAngle) * M_PI / 180.0f) * radiusX;
1333 vertices[2 * i + 3] = m_y + transY - (GLfloat)sin((2 * i + startAngle) * M_PI / 180.0f) * radiusY;
1334 }
1335 return vertices;
1336}
1337
1338//------------------ cOglCmdDrawSlope -----------------------
1339// type:
1340// 0: horizontal, rising, lower
1341// 1: horizontal, rising, upper
1342// 2: horizontal, falling, lower
1343// 3: horizontal, falling, upper
1344// 4: vertical, rising, lower
1345// 5: vertical, rising, upper
1346// 6: vertical, falling, lower
1347// 7: vertical, falling, upper
1348//-----------------------------------------------------------
1350{
1351 if (m_width <= 0 || m_height <= 0)
1352 return false;
1353
1354 bool falling = m_type & 0x02;
1355 bool vertical = m_type & 0x04;
1356
1357 int steps = 100;
1358 if (m_width < 100)
1359 steps = 25;
1360 int numVertices = steps + 2;
1361 GLfloat *vertices = new GLfloat[numVertices * 2];
1362
1363 switch (m_type) {
1364 case 0:
1365 case 4:
1366 vertices[0] = (GLfloat)(m_x + m_width);
1367 vertices[1] = (GLfloat)(m_y + m_height);
1368 break;
1369 case 1:
1370 case 5:
1371 vertices[0] = (GLfloat)m_x;
1372 vertices[1] = (GLfloat)m_y;
1373 break;
1374 case 2:
1375 case 6:
1376 vertices[0] = (GLfloat)m_x;
1377 vertices[1] = (GLfloat)(m_y + m_height);
1378 break;
1379 case 3:
1380 case 7:
1381 vertices[0] = (GLfloat)(m_x + m_width);
1382 vertices[1] = (GLfloat)m_y;
1383 break;
1384 default:
1385 vertices[0] = (GLfloat)(m_x);
1386 vertices[1] = (GLfloat)(m_y);
1387 break;
1388 }
1389
1390 for (int i = 0; i <= steps; i++) {
1391 GLfloat c = cos(i * M_PI / steps);
1392 if (falling)
1393 c = -c;
1394 if (vertical) {
1395 vertices[2 * i + 2] = (GLfloat)m_x + (GLfloat)m_width / 2.0f + (GLfloat)m_width * c / 2.0f;
1396 vertices[2 * i + 3] = (GLfloat)m_y + (GLfloat)i * ((GLfloat)m_height) / steps ;
1397 } else {
1398 vertices[2 * i + 2] = (GLfloat)m_x + (GLfloat)i * ((GLfloat)m_width) / steps ;
1399 vertices[2 * i + 3] = (GLfloat)m_y + (GLfloat)m_height / 2.0f + (GLfloat)m_height * c / 2.0f;
1400 }
1401 }
1402
1403 VertexBuffers[vbSlope]->ActivateShader();
1404 VertexBuffers[vbSlope]->SetShaderColor(m_color);
1405 VertexBuffers[vbSlope]->SetShaderProjectionMatrix(m_pFramebuffer->Width(), m_pFramebuffer->Height());
1406
1407 // not antialiased
1409 VertexBuffers[vbSlope]->DisableBlending();
1410 VertexBuffers[vbSlope]->Bind();
1411 VertexBuffers[vbSlope]->SetVertexSubData(vertices, numVertices);
1412 VertexBuffers[vbSlope]->DrawArrays(numVertices);
1413 VertexBuffers[vbSlope]->Unbind();
1414 VertexBuffers[vbSlope]->EnableBlending();
1416
1417 delete[] vertices;
1418 return true;
1419}
1420
1421//------------------ cOglCmdDrawText ------------------------
1423{
1425 if (!f)
1426 return false;
1427
1428 if (!m_length)
1429 return false;
1430
1431 VertexBuffers[vbText]->ActivateShader();
1432 VertexBuffers[vbText]->SetShaderColor(m_colorText);
1433 VertexBuffers[vbText]->SetShaderProjectionMatrix(m_pFramebuffer->Width(), m_pFramebuffer->Height());
1434
1436 VertexBuffers[vbText]->Bind();
1437
1438 int xGlyph = m_x;
1439 int fontHeight = f->Height();
1440 int bottom = f->Bottom();
1441 FT_ULong sym = 0;
1442 FT_ULong prevSym = 0;
1443 int kerning = 0;
1444
1445 // Check, if we only have symbols, which are in our atlas
1446 int unknown_char = 0;
1447 for (int i = 0; m_pSymbols[i]; i++) {
1448 if ((m_pSymbols[i] < MIN_CHARCODE) || (m_pSymbols[i] > MAX_CHARCODE)) {
1449 if (m_pSymbols[i]) {
1451 break;
1452 }
1453 }
1454 }
1455
1456 if (!unknown_char) {
1457 cOglFontAtlas *fa = f->Atlas();
1458 std::vector<GLfloat> vertices;
1459 vertices.reserve( 4 * 6 * m_length);
1460
1461 for (int i = 0; m_pSymbols[i]; i++) {
1462 sym = m_pSymbols[i];
1463
1465 // Get the glyph from the font atlas for ASCII code MIN_CHARCODE-MAX_CHARCODE
1466 g = fa->GetGlyph(sym);
1467
1468 if (!g) {
1469 LOGWARNING("openglosd: %s: could not load glyph %lx", __FUNCTION__, sym);
1470 continue;
1471 }
1472
1473 if ( m_limitX && xGlyph + g->AdvanceX() > m_limitX )
1474 break;
1475
1476 kerning = f->Kerning(g, prevSym);
1477 prevSym = sym;
1478
1479 GLfloat x2 = xGlyph + kerning + g->BearingLeft();
1480 GLfloat y2 = m_y + (fontHeight - bottom - g->BearingTop()); //top
1481 GLfloat w = g->Width();
1482 GLfloat h = g->Height();
1483
1484 vertices.push_back(x2);
1485 vertices.push_back(y2);
1486 vertices.push_back(g->OffsetX());
1487 vertices.push_back(g->OffsetY());
1488
1489 vertices.push_back(x2 + w);
1490 vertices.push_back(y2);
1491 vertices.push_back(g->OffsetX() + g->Width() / (float)fa->Width());
1492 vertices.push_back(g->OffsetY());
1493
1494 vertices.push_back(x2);
1495 vertices.push_back(y2 + h);
1496 vertices.push_back(g->OffsetX());
1497 vertices.push_back(g->OffsetY() + g->Height() / (float)fa->Height());
1498
1499 vertices.push_back(x2 + w);
1500 vertices.push_back(y2);
1501 vertices.push_back(g->OffsetX() + g->Width() / (float)fa->Width());
1502 vertices.push_back(g->OffsetY());
1503
1504 vertices.push_back(x2);
1505 vertices.push_back(y2 + h);
1506 vertices.push_back(g->OffsetX());
1507 vertices.push_back(g->OffsetY() + g->Height() / (float)fa->Height());
1508
1509 vertices.push_back(x2 + w);
1510 vertices.push_back(y2 + h);
1511 vertices.push_back(g->OffsetX() + g->Width() / (float)fa->Width());
1512 vertices.push_back(g->OffsetY() + g->Height() / (float)fa->Height());
1513
1514 xGlyph += kerning + g->AdvanceX();
1515
1516 if ( xGlyph > m_pFramebuffer->Width() - 1 )
1517 break;
1518 }
1519
1520 fa->BindTexture();
1521 VertexBuffers[vbText]->SetVertexData(vertices.data(), (vertices.size() / 4));
1522 VertexBuffers[vbText]->DrawArrays(vertices.size() / 4);
1523 } else {
1524 LOGDEBUG2(L_OPENGL, "openglosd: %s: char %d is not on the texture atlas, use single draw", __FUNCTION__, unknown_char);
1525 for (int i = 0; m_pSymbols[i]; i++) {
1526 sym = m_pSymbols[i];
1527 cOglGlyph *g = f->Glyph(sym);
1528 if (!g) {
1529 LOGWARNING("openglosd: %s: could not load glyph %lx", __FUNCTION__, sym);
1530 continue;
1531 }
1532
1533 if ( m_limitX && xGlyph + g->AdvanceX() > m_limitX )
1534 break;
1535
1536 kerning = f->Kerning(g, prevSym);
1537 prevSym = sym;
1538
1539 GLfloat x1 = xGlyph + kerning + g->BearingLeft(); // left
1540 GLfloat y1 = m_y + (fontHeight - bottom - g->BearingTop()); // top
1541 GLfloat x2 = x1 + g->Width(); // right
1542 GLfloat y2 = y1 + g->Height(); // bottom
1543
1544 GLfloat vertices[] = {
1545 x1, y2, 0.0, 1.0, // left bottom
1546 x1, y1, 0.0, 0.0, // left top
1547 x2, y1, 1.0, 0.0, // right top
1548
1549 x1, y2, 0.0, 1.0, // left bottom
1550 x2, y1, 1.0, 0.0, // right top
1551 x2, y2, 1.0, 1.0 // right bottom
1552 };
1553
1554 g->BindTexture();
1555 VertexBuffers[vbText]->SetVertexData(vertices);
1556 VertexBuffers[vbText]->DrawArrays();
1557
1558 xGlyph += kerning + g->AdvanceX();
1559
1560 if ( xGlyph > m_pFramebuffer->Width() - 1 )
1561 break;
1562 }
1563 }
1564
1566 VertexBuffers[vbText]->Unbind();
1568 return true;
1569}
1570
1571//------------------ cOglCmdDrawImage -----------------------
1573{
1574 if (m_width <= 0 || m_height <= 0)
1575 return false;
1576
1577 GLuint texture;
1578 GL_CHECK(glGenTextures(1, &texture));
1582 0,
1583 GL_RGBA,
1584 m_width,
1585 m_height,
1586 0,
1587 GL_RGBA,
1589 m_argb
1590 ));
1596
1597 GLfloat x1 = m_x; // left
1598 GLfloat y1 = m_y; // top
1599 GLfloat x2 = m_x + m_width * m_scaleX; // right
1600 GLfloat y2 = m_y + m_height * m_scaleY; // bottom
1601
1602 GLfloat quadVertices[] = {
1603 x1, y2, 0.0, 1.0, // left bottom
1604 x1, y1, 0.0, 0.0, // left top
1605 x2, y1, 1.0, 0.0, // right top
1606
1607 x1, y2, 0.0, 1.0, // left bottom
1608 x2, y1, 1.0, 0.0, // right top
1609 x2, y2, 1.0, 1.0 // right bottom
1610 };
1611
1612 VertexBuffers[vbTextureSwapBR]->ActivateShader();
1613 VertexBuffers[vbTextureSwapBR]->SetShaderAlpha(255);
1614 VertexBuffers[vbTextureSwapBR]->SetShaderProjectionMatrix(m_pFramebuffer->Width(), m_pFramebuffer->Height());
1615 VertexBuffers[vbTextureSwapBR]->SetShaderBorderColor(m_borderColor);
1616
1619 if (m_overlay)
1620 VertexBuffers[vbTextureSwapBR]->DisableBlending();
1622 VertexBuffers[vbTextureSwapBR]->SetVertexSubData(quadVertices);
1623 VertexBuffers[vbTextureSwapBR]->DrawArrays();
1624 VertexBuffers[vbTextureSwapBR]->Unbind();
1625 if (m_overlay)
1626 VertexBuffers[vbTextureSwapBR]->EnableBlending();
1629 GL_CHECK(glDeleteTextures(1, &texture));
1630
1631 return true;
1632}
1633
1634//------------------ cOglCmdDrawTexture ---------------------
1636{
1637 if (m_pImageRef->width <= 0 || m_pImageRef->height <= 0)
1638 return false;
1639
1640 GLfloat x1 = m_x; // top
1641 GLfloat y1 = m_y; // left
1642 GLfloat x2 = m_x + m_pImageRef->width * m_scaleX; // right
1643 GLfloat y2 = m_y + m_pImageRef->height * m_scaleY; // bottom
1644
1645 GLfloat quadVertices[] = {
1646 // Pos // TexCoords
1647 x1, y1, 0.0f, 0.0f, // left bottom
1648 x1, y2, 0.0f, 1.0f, // left top
1649 x2, y2, 1.0f, 1.0f, // right top
1650
1651 x1, y1, 0.0f, 0.0f, // left bottom
1652 x2, y2, 1.0f, 1.0f, // right top
1653 x2, y1, 1.0f, 0.0f // right bottom
1654 };
1655
1656 VertexBuffers[vbTextureSwapBR]->ActivateShader();
1657 VertexBuffers[vbTextureSwapBR]->SetShaderAlpha(255);
1658 VertexBuffers[vbTextureSwapBR]->SetShaderProjectionMatrix(m_pFramebuffer->Width(), m_pFramebuffer->Height());
1659 VertexBuffers[vbTextureSwapBR]->SetShaderBorderColor(m_borderColor);
1660
1664 VertexBuffers[vbTextureSwapBR]->SetVertexSubData(quadVertices);
1665 VertexBuffers[vbTextureSwapBR]->DrawArrays();
1666 VertexBuffers[vbTextureSwapBR]->Unbind();
1668
1669 return true;
1670}
1671
1672//------------------ cOglCmdStoreImage ----------------------
1694
1695//------------------ cOglCmdDropImage -----------------------
1697 if (m_pImageRef->texture != GL_NONE)
1699 m_pWait->Signal();
1700 return true;
1701}
1702
1703/******************************************************************************
1704 * cOglThread
1705 *****************************************************************************/
1707 : cThread("oglThread"),
1708 m_startWait(startWait),
1709 m_maxCacheSize(maxCacheSize * 1024 * 1024),
1710 m_pRender(device->Render())
1711{
1712 for (int i = 0; i < OGL_MAX_OSDIMAGES; i++) {
1713 m_imageCache[i].used = false;
1715 m_imageCache[i].width = 0;
1716 m_imageCache[i].height = 0;
1717 }
1718
1719 Start();
1720}
1721
1723{
1724 for (int i = 0; i < OGL_MAX_OSDIMAGES; i++) {
1725 if (m_imageCache[i].used) {
1727 }
1728 }
1729}
1730
1732{
1734 Cancel(-1);
1735}
1736
1738{
1740 Cancel(2);
1741 Cleanup();
1742 m_stalled = false;
1743}
1744
1746{
1747 while (m_stalled)
1748 cCondWait::SleepMs(10);
1749
1750 bool doSignal = false;
1751 Lock();
1752 if (m_commands.size() == 0)
1753 doSignal = true;
1754 m_commands.push(cmd);
1755 Unlock();
1756
1757 if (m_commands.size() > OGL_CMDQUEUE_SIZE) {
1758 m_stalled = true;
1759 }
1760
1761 if (doSignal || m_stalled)
1762 m_wait.Signal();
1763}
1764
1766{
1767 if (!m_maxCacheSize) {
1768 LOGERROR("openglosd: %s: cannot store image, no cache set", __FUNCTION__);
1769 return 0;
1770 }
1771
1772 if (image.Width() > m_maxTextureSize || image.Height() > m_maxTextureSize) {
1773 LOGERROR("openglosd: %s: cannot store image of %dpx x %dpx (maximum size is %dpx x %dpx) - falling back to cOsdProvider::StoreImageData()",
1775 return 0;
1776 }
1777
1778 int imgSize = image.Width() * image.Height();
1779 int newMemUsed = imgSize * sizeof(tColor) + m_memCached;
1780 if (newMemUsed > m_maxCacheSize) {
1781 float cachedMB = m_memCached / 1024.0f / 1024.0f;
1782 float maxMB = m_maxCacheSize / 1024.0f / 1024.0f;
1783 LOGERROR("openglosd: %s: Maximum size for GPU cache reached. Used: %.2fMB Max: %.2fMB", __FUNCTION__, cachedMB, maxMB);
1784 return 0;
1785 }
1786
1787 int slot = GetFreeSlot();
1788 if (!slot)
1789 return 0;
1790
1792 if (!argb) {
1793 LOGERROR("openglosd: %s: memory allocation of %d kb for OSD image failed", __FUNCTION__, (int)(imgSize * sizeof(tColor) / 1024));
1794 ClearSlot(slot);
1795 slot = 0;
1796 return 0;
1797 }
1798
1799 memcpy(argb, image.Data(), sizeof(tColor) * imgSize);
1800
1802 imageRef->width = image.Width();
1803 imageRef->height = image.Height();
1805
1806 cTimeMs timer(5000);
1807 while (imageRef->used && imageRef->texture == 0 && !timer.TimedOut())
1808 cCondWait::SleepMs(2);
1809
1810 if (imageRef->texture == GL_NONE) {
1811 LOGERROR("openglosd: %s: failed to store OSD image texture! (%s)", __FUNCTION__, timer.TimedOut() ? "timed out" : "allocation failed");
1813 slot = 0;
1814 }
1815
1816 m_memCached += imgSize * sizeof(tColor);
1817
1818 return slot;
1819}
1820
1822{
1823 Lock();
1824 int slot = 0;
1825 for (int i = 0; i < OGL_MAX_OSDIMAGES && !slot; i++) {
1826 if (!m_imageCache[i].used) {
1827 m_imageCache[i].used = true;
1828 slot = -i - 1;
1829 }
1830 }
1831 Unlock();
1832 return slot;
1833}
1834
1836{
1837 int i = -slot - 1;
1838 if (i >= 0 && i < OGL_MAX_OSDIMAGES) {
1839 Lock();
1840 m_imageCache[i].used = false;
1842 m_imageCache[i].width = 0;
1843 m_imageCache[i].height = 0;
1844 Unlock();
1845 }
1846}
1847
1849{
1850 int i = -slot - 1;
1851 if (0 <= i && i < OGL_MAX_OSDIMAGES)
1852 return &m_imageCache[i];
1853 return 0;
1854}
1855
1857{
1859 if (!imageRef)
1860 return;
1861 int imgSize = imageRef->width * imageRef->height * sizeof(tColor);
1865 dropWait.Wait();
1867}
1868
1870{
1871 if (!InitOpenGL()) {
1872 LOGERROR("openglosd: %s: Could not initiate OpenGL context", __FUNCTION__);
1873 Cleanup();
1874 m_startWait->Signal();
1875 return;
1876 }
1877
1878 if (!InitShaders()) {
1879 LOGERROR("openglosd: %s: Could not initiate shaders", __FUNCTION__);
1880 Cleanup();
1881 m_startWait->Signal();
1882 return;
1883 }
1884
1885 if (!InitVertexBuffers()) {
1886 LOGERROR("openglosd: %s: Vertex Buffers NOT initialized", __FUNCTION__);
1887 Cleanup();
1888 m_startWait->Signal();
1889 return;
1890 }
1891
1893 LOGDEBUG2(L_OPENGL, "openglosd: %s: Maximum Pixmap size: %dx%dpx", __FUNCTION__, m_maxTextureSize, m_maxTextureSize);
1894
1895 //now Thread is ready to do his job
1896 m_startWait->Signal();
1897 m_stalled = false;
1898
1899 LOGINFO("OpenGL context initialized");
1900
1901 uint64_t startFlush = 0;
1902 uint64_t endFlush = 0;
1903 bool timeReset = false;
1904
1905 while(Running()) {
1906 if (m_commands.empty()) {
1907 m_wait.Wait(20);
1908 continue;
1909 }
1910
1911 Lock();
1912 cOglCmd* cmd = m_commands.front();
1913 m_commands.pop();
1914 Unlock();
1915
1916 uint64_t start = cTimeMs::Now();
1917 if (strcmp(cmd->Description(), "InitFramebuffer") == 0 || timeReset) {
1918 startFlush = cTimeMs::Now();
1919 timeReset = false;
1920 }
1921
1922 { // start of locked context
1923 std::unique_lock<std::mutex> lock(m_mutex, std::defer_lock);
1924
1925 if (cmd->NeedsLockingAgainstStateChange())
1926 lock.lock();
1927
1928 if (!Running())
1929 continue;
1930
1931 cmd->Execute();
1932 } // end of locked context
1933
1934 LOGDEBUG2(L_OPENGL_TIME_ALL, "openglosd: %s: \"%-*s\", %dms, %d commands left, time %" PRIu64 "",
1935 __FUNCTION__, 15, cmd->Description(), (int)(cTimeMs::Now() - start), (int)(m_commands.size()), cTimeMs::Now());
1936
1937 if (strcmp(cmd->Description(), "Copy buffer to OutputFramebuffer") == 0) {
1938 endFlush = cTimeMs::Now();
1939 timeReset = true;
1940 LOGDEBUG2(L_OPENGL_TIME, "openglosd: %s: OSD Flush %dms, time %" PRIu64 "", __FUNCTION__, (int)(endFlush - startFlush), cTimeMs::Now());
1941 }
1942 delete cmd;
1943 if (m_stalled && m_commands.size() < OGL_CMDQUEUE_SIZE / 2)
1944 m_stalled = false;
1945 }
1946
1947 LOGINFO("OpenGL worker thread stopped");
1948}
1949
1954
1960{
1961 LOGDEBUG2(L_OPENGL, "openglosd: %s: Init OpenGL context", __FUNCTION__);
1962
1963 // Wait for the EGL context to be created
1964 while(!m_pRender || !m_pRender->GlInitiated()) {
1965 LOGDEBUG2(L_OPENGL, "openglosd: %s: wait for EGL context", __FUNCTION__);
1966 usleep(20000);
1967 }
1968
1969 eglAcquireContext(); // eglMakeCurrent with new eglSurface
1970
1971 GL_CHECK(LOGDEBUG2(L_OPENGL, " GL Version: \"%s\"", glGetString(GL_VERSION)));
1972 GL_CHECK(LOGDEBUG2(L_OPENGL, " GL Vendor: \"%s\"", glGetString(GL_VENDOR)));
1973 GL_CHECK(LOGDEBUG2(L_OPENGL, " GL Extensions: \"%s\"", glGetString(GL_EXTENSIONS)));
1974 GL_CHECK(LOGDEBUG2(L_OPENGL, " GL Renderer: \"%s\"", glGetString(GL_RENDERER)));
1975
1976 VertexBuffers[vbText]->EnableBlending();
1978 LOGDEBUG2(L_OPENGL, "openglosd: %s: Init OpenGL context done", __FUNCTION__);
1979
1980 return true;
1981}
1982
1984{
1985 for (int i = 0; i < stCount; i++) {
1986 cOglShader *shader = new cOglShader();
1987 if (!shader->Load((eShaderType)i))
1988 return false;
1989 Shaders[i] = shader;
1990 }
1991 LOGDEBUG2(L_OPENGL, "openglosd: %s: Shaders initialized", __FUNCTION__);
1992
1993 return true;
1994}
1995
1997{
1998 for (int i = 0; i < stCount; i++)
1999 delete Shaders[i];
2000}
2001
2003{
2004 for (int i = 0; i < vbCount; i++) {
2005 cOglVb *vb = new cOglVb(i);
2006 if (!vb->Init())
2007 return false;
2008 VertexBuffers[i] = vb;
2009 }
2010 LOGDEBUG2(L_OPENGL, "openglosd: %s: Vertex buffers initialized", __FUNCTION__);
2011
2012 return true;
2013}
2014
2016{
2017 for (int i=0; i < vbCount; i++) {
2018 delete VertexBuffers[i];
2019 }
2020}
2021
2023{
2024 LOGDEBUG2(L_OPENGL, "openglosd: %s: Cleaning up OpenGL stuff", __FUNCTION__);
2025
2029 DeleteShaders();
2031}
2032
2033/******************************************************************************
2034 * cOglPixmap
2035 *****************************************************************************/
2036cOglPixmap::cOglPixmap(std::shared_ptr<cOglThread> oglThread, int layer, const cRect &viewPort, const cRect &drawPort)
2037 : cPixmap(layer, viewPort, drawPort),
2038 m_pOglThread(oglThread)
2039{
2040 int width = drawPort.IsEmpty() ? viewPort.Width() : drawPort.Width();
2041 int height = drawPort.IsEmpty() ? viewPort.Height() : drawPort.Height();
2042
2043 if (width > m_pOglThread->MaxTextureSize() || height > m_pOglThread->MaxTextureSize()) {
2044 LOGWARNING("openglosd: %s: cannot allocate pixmap of %dpx x %dpx, clipped to %dpx x %dpx!", __FUNCTION__,
2045 width, height, std::min(width, m_pOglThread->MaxTextureSize()), std::min(height, m_pOglThread->MaxTextureSize()));
2046 width = std::min(width, m_pOglThread->MaxTextureSize());
2047 height = std::min(height, m_pOglThread->MaxTextureSize());
2048 }
2049
2050 m_pFramebuffer = new cOglFb(width, height, viewPort.Width(), viewPort.Height());
2051
2052#ifdef GRIDPOINTS
2053 // Creates a tiny font with height GRIDPOINTSTXTSIZE
2054 m_pTinyfont = cFont::CreateFont(Setup.FontOsd, GRIDPOINTSTXTSIZE);
2055#endif
2056}
2057
2059{
2060 if (!m_pOglThread->Active())
2061 return;
2062
2064#ifdef GRIDPOINTS
2065 delete m_pTinyfont;
2066#endif
2067}
2068
2070{
2071 cPixmap::MarkViewPortDirty(rect);
2072 SetDirty();
2073}
2074
2076{
2077 cPixmap::SetClean();
2078 SetDirty(false);
2079}
2080
2082{
2083 cPixmap::SetLayer(layer);
2084 SetDirty();
2085}
2086
2088{
2090 if (alpha != cPixmap::Alpha()) {
2091 cPixmap::SetAlpha(alpha);
2092 SetDirty();
2093 }
2094}
2095
2097{
2098 cPixmap::SetTile(tile);
2099 SetDirty();
2100}
2101
2103{
2104 cPixmap::SetViewPort(rect);
2105 SetDirty();
2106}
2107
2109{
2110 cPixmap::SetDrawPortPoint(point, dirty);
2111 if (dirty)
2112 SetDirty();
2113}
2114
2116{
2117 if (!m_pOglThread->Active())
2118 return;
2119
2122 SetDirty();
2124}
2125
2127{
2128 if (!m_pOglThread->Active())
2129 return;
2130
2133 SetDirty();
2135}
2136
2138{
2140}
2141
2146
2147void cOglPixmap::DrawScaledImage(const cPoint &point, const cImage &image, double factorX, double factorY, __attribute__ ((unused)) bool antiAlias)
2148{
2149 if (!m_pOglThread->Active())
2150 return;
2151
2152 tColor *argb = MALLOC(tColor, image.Width() * image.Height());
2153 if (!argb)
2154 return;
2155 memcpy(argb, image.Data(), sizeof(tColor) * image.Width() * image.Height());
2156
2157 m_pOglThread->DoCmd(new cOglCmdDrawImage(m_pFramebuffer, argb, image.Width(), image.Height(), point.X(), point.Y(), true, factorX, factorY));
2158#ifdef GRIDRECT
2160#endif
2161 SetDirty();
2162 MarkDrawPortDirty(cRect(point, cSize(image.Width() * factorX, image.Height() * factorY)).Intersected(DrawPort().Size()));
2163}
2164
2166{
2167 if (!m_pOglThread->Active())
2168 return;
2169
2171 sOglImage *img = m_pOglThread->GetImageRef(imageHandle);
2173#ifdef GRIDRECT
2175#endif
2176 SetDirty();
2177 MarkDrawPortDirty(cRect(point, cSize(img->width * factorX, img->height * factorY)).Intersected(DrawPort().Size()));
2178 }
2179}
2180
2182{
2183 cRect r(point.X(), point.Y(), 1, 1);
2184 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, r.X(), r.Y(), r.Width(), r.Height(), color));
2185#ifdef GRIDRECT
2187#endif
2188 SetDirty();
2190}
2191
2193{
2194 if (!m_pOglThread->Active())
2195 return;
2196
2198 bool specialColors = colorFg || colorBg;
2199 tColor *argb = MALLOC(tColor, bitmap.Width() * bitmap.Height());
2200 if (!argb)
2201 return;
2202
2203 tColor *p = argb;
2204 for (int py = 0; py < bitmap.Height(); py++)
2205 for (int px = 0; px < bitmap.Width(); px++) {
2206 tIndex index = *bitmap.Data(px, py);
2207 *p++ = (!index && overlay) ? clrTransparent :
2208 (specialColors ? (index == 0 ? colorBg : index == 1 ? colorFg :
2209 bitmap.Color(index)) : bitmap.Color(index));
2210 }
2211
2212 m_pOglThread->DoCmd(new cOglCmdDrawImage(m_pFramebuffer, argb, bitmap.Width(), bitmap.Height(), point.X(), point.Y(), true));
2213#ifdef GRIDRECT
2215#endif
2216
2217 SetDirty();
2218 MarkDrawPortDirty(cRect(cPoint(point.X(), point.Y()), cSize(bitmap.Width(), bitmap.Height())).Intersected(DrawPort().Size()));
2219}
2220
2221void cOglPixmap::DrawText(const cPoint &point, const char *s, tColor colorFg, tColor colorBg, const cFont *font, int width, int height, int alignment)
2222{
2223 DrawTextInternal(point, s, colorFg, colorBg, font, width, height, alignment, false);
2224}
2225
2226#ifdef GRIDPOINTS
2227void cOglPixmap::DrawGridText(const cPoint &point, const char *s, tColor colorFg, tColor colorBg, const cFont *font, int width, int height, int alignment)
2228{
2229 DrawTextInternal(point, s, colorFg, colorBg, font, width, height, alignment, true);
2230}
2231#endif
2232
2233void cOglPixmap::DrawTextInternal(const cPoint &point, const char *s, tColor colorFg, tColor colorBg, const cFont *font, int width, int height, int alignment, bool isGridText)
2234{
2235 if (!m_pOglThread->Active())
2236 return;
2237
2239 int len = s ? Utf8StrLen(s) : 0;
2240 unsigned int *symbols = MALLOC(unsigned int, len + 1);
2241 if (!symbols)
2242 return;
2243
2244 if (len)
2245 Utf8ToArray(s, symbols, len + 1);
2246 else
2247 symbols[0] = 0;
2248
2249 int x = point.X();
2250 int y = point.Y();
2251 int w = font->Width(s);
2252 int h = font->Height();
2253 int limitX = 0;
2254 int cw = width ? width : w;
2255 int ch = height ? height : h;
2256
2257 // workaround for messages in SkinElchiHD
2258 if (width > ViewPort().Width() && !x && !isGridText)
2259 x = ViewPort().Width() - w;
2260
2261 cRect r(x, y, cw, ch);
2262
2263 if (colorBg != clrTransparent)
2264 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, r.X(), r.Y(), r.Width(), r.Height(), colorBg));
2265
2266 if (width || height)
2267 limitX = x + cw;
2268
2269 if (width) {
2270 if ((alignment & taLeft) != 0) {
2271 if ((alignment & taBorder) != 0)
2272 x += std::max(h / TEXT_ALIGN_BORDER, 1);
2273 } else if ((alignment & taRight) != 0) {
2274 if (w < width)
2275 x += width - w;
2276 if ((alignment & taBorder) != 0)
2277 x -= std::max(h / TEXT_ALIGN_BORDER, 1);
2278 } else { // taCentered
2279 if (w < width)
2280 x += (width - w) / 2;
2281 }
2282 }
2283
2284 if (height) {
2285 if ((alignment & taTop) != 0)
2286 ;
2287 else if ((alignment & taBottom) != 0) {
2288 if (h < height)
2289 y += height - h;
2290 } else { // taCentered
2291 if (h < height)
2292 y += (height - h) / 2;
2293 }
2294 }
2295
2296 m_pOglThread->DoCmd(new cOglCmdDrawText(m_pFramebuffer, x, y, symbols, limitX, font->FontName(), font->Size(), colorFg, len));
2297
2298#ifdef GRIDTEXT
2299 if (!isGridText)
2301#endif
2302
2303 SetDirty();
2305}
2306
2308{
2309 if (!m_pOglThread->Active())
2310 return;
2311
2313 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, rect.X(), rect.Y(), rect.Width(), rect.Height(), color));
2314#ifdef GRIDRECT
2316#endif
2317
2318 SetDirty();
2320}
2321
2323{
2324 if (!m_pOglThread->Active())
2325 return;
2326
2328 m_pOglThread->DoCmd(new cOglCmdDrawEllipse(m_pFramebuffer, rect.X(), rect.Y(), rect.Width(), rect.Height(), color, quadrants));
2329#ifdef GRIDRECT
2331#endif
2332
2333 SetDirty();
2335}
2336
2338{
2339 if (!m_pOglThread->Active())
2340 return;
2341
2343 m_pOglThread->DoCmd(new cOglCmdDrawSlope(m_pFramebuffer, rect.X(), rect.Y(), rect.Width(), rect.Height(), color, type));
2344#ifdef GRIDRECT
2346#endif
2347
2348 SetDirty();
2350}
2351
2352void cOglPixmap::Render(const cPixmap *pixmap, const cRect &source, const cPoint &dest)
2353{
2355}
2356
2357void cOglPixmap::Copy(const cPixmap *pixmap, const cRect &source, const cPoint &dest)
2358{
2359 // render without respect to alpha values
2361}
2362
2363void cOglPixmap::RenderPixmapInternal(const cPixmap *pixmap, const cRect &source, const cPoint &dest, bool useAlpha)
2364{
2365 LOGDEBUG2(L_OPENGL, "openglosd: %s: %s", __FUNCTION__, useAlpha ? "Render()" : "Copy()");
2366
2367 if (!m_pOglThread->Active() || !pixmap || source.IsEmpty())
2368 return;
2369
2371
2372 const cOglPixmap *sourceOgl = dynamic_cast<const cOglPixmap *>(pixmap);
2373
2374 // Self-rendering is not allowed according to VDR API
2375 if (sourceOgl && sourceOgl != this) {
2376 cRect sourceRect = source.Intersected(cRect(0, 0, sourceOgl->DrawPort().Width(), sourceOgl->DrawPort().Height()));
2377 sourceRect.SetX(sourceRect.X() + sourceOgl->DrawPort().X());
2378 sourceRect.SetY(sourceRect.Y() + sourceOgl->DrawPort().Y());
2379
2380 cRect destRect(dest, sourceRect.Size());
2382 if (clippedDest.IsEmpty())
2383 return;
2384
2385 sourceRect.SetX(sourceRect.X() + clippedDest.X() - destRect.X());
2386 sourceRect.SetY(sourceRect.Y() + clippedDest.Y() - destRect.Y());
2387 sourceRect.SetWidth(clippedDest.Width());
2388 sourceRect.SetHeight(clippedDest.Height());
2389 if (sourceRect.IsEmpty())
2390 return;
2391
2393 sourceOgl->Framebuffer(),
2394 sourceRect,
2395 clippedDest.Point(),
2396 useAlpha ? sourceOgl->Alpha() : ALPHA_OPAQUE));
2397
2398 SetDirty();
2400
2401 return;
2402 }
2403
2404 if (!sourceOgl)
2405 LOGWARNING("openglosd: %s: %s is not implemented in OpenGl OSD for your VDR version", __FUNCTION__, useAlpha ? "Render()" : "Copy()");
2406}
2407
2409{
2410 LOGWARNING("openglosd: %s: %d %d not implemented in OpenGl OSD", __FUNCTION__, source.X(), dest.X());
2411}
2412
2414{
2415 LOGWARNING("openglosd: %s: %d %d not implemented in OpenGl OSD", __FUNCTION__, source.X(), dest.X());
2416}
2417
2418#ifdef GRIDPOINTS
2419void cOglPixmap::DrawGridRect(const cRect &rect, int offset, int size, tColor clr, tColor bg, const cFont *font)
2420{
2421 int x1 = rect.X() + offset;
2422 int x2 = rect.X() + rect.Width() + offset;
2423 int y1 = rect.Y();
2424 int y2 = rect.Y() + rect.Height();
2425 char p1[10];
2426 char p2[10];
2427 char p3[10];
2428 char p4[10];
2429 sprintf(p1, "%d.%d", x1, y1);
2430 sprintf(p2, "%d.%d", x2, y1);
2431 sprintf(p3, "%d.%d", x1, y2);
2432 sprintf(p4, "%d.%d", x2, y2);
2433
2434 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, x1, y1, size, size, clr));
2435#ifdef GRIDPOINTSTEXT
2437#endif
2438 if (Rect.Width() && Rect.Height()) {
2439 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, x2, y1, size, size, clr));
2440 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, x1, y2, size, size, clr));
2441 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, x2, y2, size, size, clr));
2442#ifdef GRIDPOINTSTEXT
2446#endif
2447 }
2448}
2449#endif
2450
2451/******************************************************************************
2452 * cOglOsd
2453 *****************************************************************************/
2455
2456cOglOsd::cOglOsd(int left, int top, uint level, std::shared_ptr<cOglThread> oglThread, cSoftHdDevice *device)
2457 : cOsd(left, top, level),
2458 m_pOglThread(oglThread),
2459 m_isSubtitleOsd(level == 10 ? true : false),
2460 m_pDevice(device)
2461{
2462 int osdWidth = 0;
2463 int osdHeight = 0;
2464 double pixelAspect;
2466 LOGDEBUG2(L_OSD, "openglosd: %s: New Osd %p osdLeft %d osdTop %d screenWidth %d screenHeight %d", __FUNCTION__, this, left, top, osdWidth, osdHeight);
2467
2468 m_maxPixmapSize.Set(m_pOglThread->MaxTextureSize(), m_pOglThread->MaxTextureSize());
2469
2470 if (!OutputFramebuffer) {
2473 }
2474}
2475
2477{
2478 if (!m_pOglThread->Active() || !Active() || !m_pBufferFramebuffer)
2479 return;
2480
2481 LOGDEBUG2(L_OSD, "openglosd: %s: Delete Osd %p", __FUNCTION__, this);
2483
2484 SetActive(false); // OsdClose() is done in cOglCmdCopyBufferToOutputFb()
2487}
2488
2490{
2491 cRect r;
2492 if (numAreas > 1)
2493 m_isSubtitleOsd = true;
2494 for (int i = 0; i < numAreas; i++)
2495 r.Combine(cRect(areas[i].x1, areas[i].y1, areas[i].Width(), areas[i].Height()));
2496
2497 tArea area = { r.Left(), r.Top(), r.Right(), r.Bottom(), 32 };
2498
2499 // now we know the actual osd size, create double buffer frame buffer
2503 }
2504 m_pBufferFramebuffer = new cOglFb(r.Width(), r.Height(), r.Width(), r.Height());
2507 initiated.Wait();
2508
2509 return cOsd::SetAreas(&area, 1);
2510}
2511
2513{
2514 if (!m_pOglThread->Active())
2515 return NULL;
2516
2519 if (cOsd::AddPixmap(p)) {
2520 // find a free slot
2521 for (int i = 0; i < m_pOglPixmaps.Size(); i++) {
2522 if (!m_pOglPixmaps[i])
2523 return m_pOglPixmaps[i] = p;
2524 }
2525 m_pOglPixmaps.Append(p);
2526 return p;
2527 }
2528 delete p;
2529
2530 return NULL;
2531}
2532
2534{
2535 if (!m_pOglThread->Active())
2536 return;
2537 if (!Pixmap)
2538 return;
2539
2541 int start = 1;
2542 if (m_isSubtitleOsd)
2543 start = 0;
2544 for (int i = start; i < m_pOglPixmaps.Size(); i++) {
2545 if (m_pOglPixmaps[i] == Pixmap) {
2546 if (Pixmap->Layer() >= 0)
2547 m_pOglPixmaps[0]->MarkViewPortDirty(m_pOglPixmaps[i]->ViewPort());
2548
2549 m_pOglPixmaps[i] = NULL;
2550 if (i)
2551 cOsd::DestroyPixmap(Pixmap);
2552
2553 return;
2554 }
2555 }
2556}
2557
2559{
2560 if (!m_pOglThread->Active() || !Active())
2561 return;
2562
2563 LOGDEBUG2(L_OSD, "openglosd: %s: Flush Osd %p", __FUNCTION__, this);
2565 // check for dirty areas
2566 m_pDirtyViewport.Set(0, 0, 0, 0);
2567 for (int i = 0; i < m_pOglPixmaps.Size(); i++) {
2568 if (m_pOglPixmaps[i] && m_pOglPixmaps[i]->IsDirty()) {
2569 if (m_isSubtitleOsd)
2570 m_pDirtyViewport.Combine(m_pOglPixmaps[i]->DirtyViewPort().Size());
2571 else
2573
2574 m_pOglPixmaps[i]->SetClean();
2575 }
2576 }
2577
2578 if (m_pDirtyViewport.IsEmpty())
2579 return;
2580
2581 // clear private buffer within the dirty area
2583 m_pDirtyViewport.X(),
2584 m_pDirtyViewport.Y(),
2585 m_pDirtyViewport.Width(),
2586 m_pDirtyViewport.Height(),
2588
2589 // render pixmap textures blended to private buffer
2590 for (int layer = 0; layer < MAXPIXMAPLAYERS; layer++) {
2591 for (int i = 0; i < m_pOglPixmaps.Size(); i++) {
2592 if (!m_pOglPixmaps[i])
2593 continue;
2594
2595 if (m_pOglPixmaps[i]->Layer () != layer)
2596 continue;
2597
2598 if (m_isSubtitleOsd && !m_pDirtyViewport.Intersects(m_pOglPixmaps[i]->ViewPort().Size()))
2599 continue;
2600
2601 if (!m_isSubtitleOsd && !m_pDirtyViewport.Intersects(m_pOglPixmaps[i]->ViewPort()))
2602 continue;
2603
2604 bool alphablending = layer == 0 ? false : true; // decide wether to render (with alpha) or copy a pixmap
2605 m_pOglThread->DoCmd(new cOglCmdRenderFbToBufferFb(m_pOglPixmaps[i]->Framebuffer(),
2607 m_isSubtitleOsd ? 0 : m_pOglPixmaps[i]->ViewPort().X(),
2608 m_isSubtitleOsd ? 0 : m_pOglPixmaps[i]->ViewPort().Y(),
2609 m_pOglPixmaps[i]->Alpha(),
2610 m_pOglPixmaps[i]->DrawPort().X(),
2611 m_pOglPixmaps[i]->DrawPort().Y(),
2612 m_pDirtyViewport.X(),
2613 m_pDirtyViewport.Top(),
2614 m_pDirtyViewport.Width(),
2615 m_pDirtyViewport.Height(),
2616 alphablending));
2617 }
2618 }
2619 // copy the private buffer to output framebuffer
2621
2623 Left() + (m_isSubtitleOsd ? m_pOglPixmaps[0]->ViewPort().X() : 0),
2624 Top() + (m_isSubtitleOsd ? m_pOglPixmaps[0]->ViewPort().Y() : 0), 1, m_pDevice));
2625}
2626
2627void cOglOsd::DrawScaledBitmap(int x, int y, const cBitmap &Bitmap, double FactorX, double FactorY, bool AntiAlias)
2628{
2629 if (!m_pOglPixmaps[0])
2630 return;
2631
2632 std::unique_ptr<cBitmap> scaledBitmap;
2633 const cBitmap *b = &Bitmap;
2634
2635 if (!DoubleEqual(FactorX, 1.0) || !DoubleEqual(FactorY, 1.0)) {
2636 scaledBitmap.reset(Bitmap.Scaled(FactorX, FactorY, AntiAlias));
2637 b = scaledBitmap.get();
2638 }
2639
2640 int xNew = x;
2641 int yNew = y;
2642
2643 const cRect &viewport = m_pOglPixmaps[0]->ViewPort();
2644 if (m_isSubtitleOsd && (x >= viewport.X()))
2645 xNew -= viewport.X();
2646 if (m_isSubtitleOsd && (y >= viewport.Y()))
2647 yNew -= viewport.Y();
2648
2649 m_pOglPixmaps[0]->DrawBitmap(cPoint(xNew, yNew), *b);
2650}
OpenGL OSD Glyph on a Texture Atlas.
Definition openglosd.h:146
OpenGL command: Fill a framebuffer.
Definition openglosd.h:508
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:548
GLfloat * CreateVerticesFull(int &)
GLfloat * CreateVerticesHalf(int &)
GLfloat * CreateVerticesQuadrant(int &)
virtual bool Execute(void)
OpenGL command: Draw an image.
Definition openglosd.h:632
virtual bool Execute(void)
tColor * m_argb
Definition openglosd.h:649
OpenGL command: Draw a rectangle.
Definition openglosd.h:525
virtual bool Execute(void)
OpenGL command: Draw a slope.
Definition openglosd.h:577
virtual bool Execute(void)
OpenGL command: Draw a text.
Definition openglosd.h:602
cString m_fontName
Definition openglosd.h:622
unsigned int * m_pSymbols
Definition openglosd.h:624
virtual bool Execute(void)
OpenGL command: Draw a texture.
Definition openglosd.h:661
virtual bool Execute(void)
sOglImage * m_pImageRef
Definition openglosd.h:675
OpenGL command: Drop image from cache.
Definition openglosd.h:705
sOglImage * m_pImageRef
Definition openglosd.h:715
cCondWait * m_pWait
Definition openglosd.h:716
virtual bool Execute(void)
OpenGL command: Fill a polygon.
Definition openglosd.h:491
GLint m_color
Definition openglosd.h:500
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: Render a framebuffer into another one.
Definition openglosd.h:468
virtual bool Execute(void)
OpenGL command: Store image in the cache.
Definition openglosd.h:686
sOglImage * m_pImageRef
Definition openglosd.h:696
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:849
bool m_isSubtitleOsd
true, if this is a subtitle osd
Definition openglosd.h:851
cSoftHdDevice * m_pDevice
pointer to cSofthdDevice
Definition openglosd.h:854
cOglFb * m_pBufferFramebuffer
all pixmaps are composed onto this framebuffer after each other, before this one is blit onto the OSD...
Definition openglosd.h:847
static cOglOutputFb * OutputFramebuffer
main OSD output framebuffer - this keeps our finished "OSD" (one per OSD)
Definition openglosd.h:845
virtual void Flush(void)
virtual eOsdError SetAreas(const tArea *, int)
cRect m_pDirtyViewport
the dirty viewport
Definition openglosd.h:853
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:850
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:852
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:781
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:815
std::shared_ptr< cOglThread > m_pOglThread
Definition openglosd.h:816
virtual void SetTile(bool)
virtual void SetDirty(bool dirty=true)
Definition openglosd.h:790
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 &)
void RenderPixmapInternal(const cPixmap *, const cRect &, const cPoint &, bool)
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:759
void DoCmd(cOglCmd *)
long m_maxCacheSize
Definition openglosd.h:760
bool InitOpenGL(void)
bool InitVertexBuffers(void)
bool m_stalled
Definition openglosd.h:755
void CleanupImageCache(void)
sOglImage m_imageCache[OGL_MAX_OSDIMAGES]
Definition openglosd.h:758
int GetFreeSlot(void)
void Stop(void)
bool InitShaders(void)
cCondWait * m_startWait
Definition openglosd.h:753
cOglThread(cCondWait *startWait, int maxCacheSize, cSoftHdDevice *device)
cCondWait m_wait
Definition openglosd.h:754
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:761
sOglImage * GetImageRef(int)
std::mutex m_mutex
Definition openglosd.h:762
GLint m_maxTextureSize
Definition openglosd.h:757
void DeleteVertexBuffers(void)
std::queue< cOglCmd * > m_commands
Definition openglosd.h:756
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:719
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:720
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.