vdr-plugin-softhddevice-drm-gles 1.6.2
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
51// This maybe useful for skin developing and marks the rects of the single draws
52#ifdef GRIDPOINTS
53#define GRIDPOINTSTEXT 1
54#define GRIDRECT 1
55#define GRIDTEXT 0
56#define GRIDPOINTSIZE 3
57#define GRIDPOINTOFFSET 4
58#define GRIDPOINTSTXTSIZE 14
59#define GRIDPOINTBG clrTransparent
60#define GRIDPOINTCLR 0xFFFF0000
61#endif
62
63/****************************************************************************************
64 * Helpers
65 ***************************************************************************************/
66static void ConvertColor(const GLint &colARGB, glm::vec4 &col) {
67 col.a = ((colARGB & 0xFF000000) >> 24) / 255.0;
68 col.r = ((colARGB & 0x00FF0000) >> 16) / 255.0;
69 col.g = ((colARGB & 0x0000FF00) >> 8 ) / 255.0;
70 col.b = ((colARGB & 0x000000FF) ) / 255.0;
71}
72
73/****************************************************************************************
74 * cOglShader
75 ***************************************************************************************/
77
79{
81}
82
84{
85 const char *vertexCode = NULL;
86 const char *fragmentCode = NULL;
87
88 m_type = type;
89 switch (m_type) {
90 case stRect:
93 break;
94 case stTexture:
97 break;
98 case stTextureSwapBR:
101 break;
102 case stText:
105 break;
106 default:
107 LOGERROR("openglosd: %s: unknown shader type", __FUNCTION__);
108 break;
109 }
110
111 if (vertexCode == NULL || fragmentCode == NULL) {
112 LOGERROR("openglosd: %s: error reading shader", __FUNCTION__);
113 return false;
114 }
115
117 LOGERROR("openglosd: %s: error compiling shader", __FUNCTION__);
118 return false;
119 }
120
121 return true;
122}
123
128
133
135{
137}
138
140{
142}
143
145{
147}
148
149void cOglShader::SetMatrix4(const GLchar *name, const glm::mat4 &matrix)
150{
152}
153
154bool cOglShader::Compile(const char *vertexCode, const char *fragmentCode)
155{
157
158 // vertex shader
163 return false;
164
165 // fragment shader
170 return false;
171
172 // link program
176 GL_CHECK(glBindAttribLocation(m_id, 0, "position"));
177 GL_CHECK(glBindAttribLocation(m_id, 1, "texCoords"));
179 if (!CheckCompileErrors(m_id, true))
180 return false;
181
182 // delete the shaders as they're linked into our program now and no longer necessary
185 return true;
186}
187
190 GLchar infoLog[1024];
191 if (!program) {
193 if (!success) {
194 GL_CHECK(glGetShaderInfoLog(object, 1024, NULL, infoLog));
195 LOGERROR("openglosd: %s: Compile-time error: Type: %d - %s", __FUNCTION__, m_type, infoLog);
196 return false;
197 }
198 } else {
200 if (!success) {
201 GL_CHECK(glGetProgramInfoLog(object, 1024, NULL, infoLog));
202 LOGERROR("openglosd: %s: Link-time error: Type: %d - %s", __FUNCTION__, m_type, infoLog);
203 return false;
204 }
205 }
206 return true;
207}
208
209#define KERNING_UNKNOWN (-10000)
210/****************************************************************************************
211 * cOglGlyph
212 ***************************************************************************************/
214 : m_charCode(charCode),
215 m_bearingLeft(ftGlyph->left),
216 m_bearingTop(ftGlyph->top),
217 m_width(ftGlyph->bitmap.width),
218 m_height(ftGlyph->bitmap.rows),
219 m_pBuffer(ftGlyph->bitmap.buffer),
220 m_advanceX(ftGlyph->root.advance.x >> 16) // value in 1/2^16 pixel
221{
222}
223
229
231{
232 for (int i = m_pKerningCache.Size(); --i > 0; ) {
233 if (m_pKerningCache[i].prevSym == prevSym)
234 return m_pKerningCache[i].kerning;
235 }
236 return KERNING_UNKNOWN;
237}
238
239void cOglGlyph::SetKerningCache(FT_ULong prevSym, int kerning)
240{
241 m_pKerningCache.Append(tKerning(prevSym, kerning));
242}
243
248
276
277/****************************************************************************************
278 * cOglFontAtlas
279 ***************************************************************************************/
281{
282 int maxAtlasWidth;
284
285 FT_Set_Pixel_Sizes(face, 0, height);
286 FT_GlyphSlot g = face->glyph;
287
288 int rowW = 0;
289 int rowH = 0;
290
291 // Find the minimum size for the texture holding all visible ASCII characters
292 for (int i = MIN_CHARCODE; i <= MAX_CHARCODE; i++) {
294 LOGDEBUG2(L_OPENGL, "openglosd: %s: Loading char %d failed!", __FUNCTION__, i);
295 continue;
296 }
297
298 // do some glyph manipulation
301 if (FT_Stroker_New(g->library, &stroker)) {
302 LOGERROR("openglosd: %s: FT_Stroker_New error!", __FUNCTION__);
303 return;
304 }
305
306 float outlineWidth = 0.25f;
309
310 if (FT_Get_Glyph(g, &ftGlyph)) {
311 LOGERROR("openglosd: %s: FT_Get_Glyph error!", __FUNCTION__);
312 return;
313 }
314
316 LOGERROR("openglosd: %s: FT_Glyph_StrokeBoder error!", __FUNCTION__);
317 return;
318 }
319
321
323 LOGERROR("openglosd: %s: FT_Glyph_To_Bitmap error!", __FUNCTION__);
324 return;
325 }
326
328
329 if (rowW + bGlyph->bitmap.width + 1 >= (unsigned int)maxAtlasWidth) {
330 m_width = std::max(m_width, rowW);
331 m_height += rowH;
332 rowW = 0;
333 rowH = 0;
334 }
335 rowW += bGlyph->bitmap.width + 1;
336 rowH = std::max(rowH, (int)bGlyph->bitmap.rows);
337
339 }
340
341 m_width = std::max(m_width, rowW);
342 m_height += rowH;
343
344 // Create a texture that will be used to hold all ASCII glyphs
347 LOGDEBUG2(L_OPENGL, "openglosd: %s: Try creating font atlas texture with w %d h %d (max %d)", __FUNCTION__, m_width, m_height, maxAtlasWidth);
348
351 0,
353 m_width,
354 m_height,
355 0,
358 0
359 ));
360
366
367 int offsetX = 0;
368 int offsetY = 0;
369
370 rowH = 0;
371
372 // Now do the real upload
373 for (FT_ULong i = MIN_CHARCODE; i <= MAX_CHARCODE; i++) {
375 LOGWARNING("openglosd: %s: Loading char %c failed!", __FUNCTION__, i);
376 continue;
377 }
378
379 // do some glyph manipulation
382 if (FT_Stroker_New(g->library, &stroker)) {
383 LOGERROR("openglosd: %s: FT_Stroker_New error!", __FUNCTION__);
384 return;
385 }
386
387 float outlineWidth = 0.25f;
390
391 if (FT_Get_Glyph(g, &ftGlyph)) {
392 LOGERROR("openglosd: %s: FT_Get_Glyph error!", __FUNCTION__);
393 return;
394 }
395
397 LOGERROR("openglosd: %s: FT_Glyph_StrokeBoder error!", __FUNCTION__);
398 return;
399 }
400
402
404 LOGERROR("openglosd: %s: FT_Glyph_To_Bitmap error!", __FUNCTION__);
405 return;
406 }
408
409 // pushing the glyphs to the texture
410 if (offsetX + bGlyph->bitmap.width + 1 >= (unsigned int)maxAtlasWidth) {
411 offsetY += rowH;
412 rowH = 0;
413 offsetX = 0;
414 }
415
418 0,
419 offsetX,
420 offsetY,
421 bGlyph->bitmap.width,
422 bGlyph->bitmap.rows,
425 bGlyph->bitmap.buffer
426 ));
427
429 rowH = std::max(rowH, (int)bGlyph->bitmap.rows);
430 offsetX += bGlyph->bitmap.width + 1;
431
433 }
434
436 LOGDEBUG2(L_OPENGL, "openglosd: %s: Created a %d x %d (%d kB) FontAtlas for fontsize %d, rowH %d, rowW %d",
437 __FUNCTION__, m_width, m_height, m_width * m_height / 1024, height, rowH, rowW);
438}
439
441 if (m_texture)
443
444 for (FT_ULong i = MIN_CHARCODE; i <= MAX_CHARCODE; i++) {
445 if (m_pGlyph[i - MIN_CHARCODE]) {
446 delete m_pGlyph[i - MIN_CHARCODE];
447 m_pGlyph[i - MIN_CHARCODE] = nullptr;
448 }
449 }
450}
451
454 return nullptr;
455
456 return m_pGlyph[sym - MIN_CHARCODE];
457}
458
462
463/****************************************************************************************
464 * cOglFont
465 ***************************************************************************************/
468bool cOglFont::s_initiated = false;
469
471 : m_name(fontName),
472 m_size(charHeight)
473{
475 if (error)
476 LOGERROR("openglosd: %s: failed to open %s!", __FUNCTION__, *m_name);
477
480 int count = 0;
481 int minIndex = 0;
482 int maxIndex = 0;
483
487 while (gindex != 0) {
488 count++;
490 minIndex = std::min(minIndex, (int)gindex);
491 maxIndex = std::max(maxIndex, (int)gindex);
492 }
493
494 FT_Set_Char_Size(m_face, 0, m_size * 64, 0, 0);
495 m_height = (m_face->size->metrics.ascender - m_face->size->metrics.descender + 63) / 64;
496 m_bottom = abs((m_face->size->metrics.descender - 63) / 64);
498 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);
499}
500
502{
503 delete m_pAtlas;
505}
506
507cOglFont *cOglFont::Get(const char *name, int charHeight)
508{
509 if (!s_pFonts)
510 Init();
511
512 cOglFont *font;
513 for (font = s_pFonts->First(); font; font = s_pFonts->Next(font))
514 if (!strcmp(font->Name(), name) && charHeight == font->Size()) {
515 return font;
516 }
517 font = new cOglFont(name, charHeight);
518 s_pFonts->Add(font);
519
520 return font;
521}
522
524{
526 LOGERROR("openglosd: %s: failed to initialize FreeType library!", __FUNCTION__);
527 return;
528 }
530 s_initiated = true;
531}
532
534{
535 if (!s_initiated)
536 return;
537 delete s_pFonts;
538 s_pFonts = 0;
540 LOGERROR("openglosd: %s: failed to deinitialize FreeType library!", __FUNCTION__);
541
542 s_ftLib = 0;
543}
544
546{
547 // Non-breaking space:
548 if (charCode == 0xA0)
549 charCode = 0x20;
550
551 // Lookup in cache:
552 for (cOglGlyph *g = m_glyphCache.First(); g; g = m_glyphCache.Next(g)) {
553 if (g->CharCode() == charCode) {
554 return g;
555 }
556 }
557
559
561 // Load glyph image into the slot (erase previous one):
563 if (error) {
564 LOGERROR("openglosd: %s: FT_Error (0x%02x) : %s", __FUNCTION__, FT_Errors[error].code, FT_Errors[error].message);
565 return NULL;
566 }
567
571 if (error) {
572 LOGERROR("openglosd: %s: FT_Stroker_New FT_Error (0x%02x) : %s", __FUNCTION__, FT_Errors[error].code, FT_Errors[error].message);
573 return NULL;
574 }
575 float outlineWidth = 0.25f;
577
578 error = FT_Get_Glyph(m_face->glyph, &ftGlyph);
579 if (error) {
580 LOGERROR("openglosd: %s: FT_Get_Glyph FT_Error (0x%02x) : %s", __FUNCTION__, FT_Errors[error].code, FT_Errors[error].message);
581 return NULL;
582 }
583
585 if (error) {
586 LOGERROR("openglosd: %s: FT_Glyph_StrokeBorder FT_Error (0x%02x) : %s", __FUNCTION__, FT_Errors[error].code, FT_Errors[error].message);
587 return NULL;
588 }
590
592 if (error) {
593 LOGERROR("openglosd: %s: FT_Glyph_To_Bitmap FT_Error (0x%02x) : %s", __FUNCTION__, FT_Errors[error].code, FT_Errors[error].message);
594 return NULL;
595 }
596
598 glyph->LoadTexture();
599 m_glyphCache.Add(glyph);
601
602 return glyph;
603}
604
606{
607 int kerning = 0;
608 if (glyph && prevSym) {
609 kerning = glyph->GetKerningCache(prevSym);
610 if (kerning == KERNING_UNKNOWN) {
615 kerning = delta.x / 64;
616 glyph->SetKerningCache(prevSym, kerning);
617 }
618 }
619
620 return kerning;
621}
622
623/****************************************************************************************
624 * cOglFb
625 ***************************************************************************************/
627 : m_width(width),
628 m_height(height),
629 m_viewPortWidth(viewPortWidth),
630 m_viewPortHeight(viewPortHeight)
631{
633 m_scrollable = true;
634}
635
643
668
676
682
684{
685 if (!m_initiated)
686 return false;
688 return true;
689}
690
691/****************************************************************************************
692 * cOglOutputFb
693 ***************************************************************************************/
718
725
726/****************************************************************************************
727 * cOglVb
728 ***************************************************************************************/
730
731bool cOglVb::Init(void)
732{
733 switch (m_type) {
734 case vbTexture: // Texture VBO definition
735 m_sizeVertex1 = 2;
736 m_sizeVertex2 = 2;
737 m_numVertices = 6;
740 break;
741 case vbTextureSwapBR: // Texture VBO definition, BR swapped
742 m_sizeVertex1 = 2;
743 m_sizeVertex2 = 2;
744 m_numVertices = 6;
747 break;
748 case vbRect: // Rectangle VBO definition
749 m_sizeVertex1 = 2;
750 m_sizeVertex2 = 0;
751 m_numVertices = 4;
754 break;
755 case vbEllipse: // Ellipse VBO definition
756 m_sizeVertex1 = 2;
757 m_sizeVertex2 = 0;
758 m_numVertices = 182;
761 break;
762 case vbSlope: // Slope VBO definition
763 m_sizeVertex1 = 2;
764 m_sizeVertex2 = 0;
765 m_numVertices = 102;
768 break;
769 case vbText: // Text VBO definition
770 m_sizeVertex1 = 2;
771 m_sizeVertex2 = 2;
772 m_numVertices = 6;
775 break;
776 default:
777 break;
778 }
779
782
784
787 if (m_sizeVertex2 > 0) {
790 }
791
793
794 return true;
795}
796
807
812
814{
815 Shaders[m_shader]->Use();
816}
817
823
828
830{
831 glm::vec4 col;
833 Shaders[m_shader]->SetVector4f("inColor", col.r, col.g, col.b, col.a);
834}
835
837{
838 glm::vec4 col;
840 Shaders[m_shader]->SetVector4f("bColor", col.r, col.g, col.b, col.a);
841}
842
844{
845 Shaders[m_shader]->SetInteger("screenTexture", value);
846}
847
849{
850 Shaders[m_shader]->SetVector4f("alpha", 1.0f, 1.0f, 1.0f, (GLfloat)(alpha) / 255.0f);
851}
852
854{
855 glm::mat4 projection = glm::ortho(0.0f, (GLfloat)width, (GLfloat)height, 0.0f, -1.0f, 1.0f);
856 Shaders[m_shader]->SetMatrix4("projection", projection);
857}
858
867
876
878{
879 if (count == 0)
882}
883
884/****************************************************************************************
885 * cOpenGLCmd
886 ***************************************************************************************/
887
888//------------------ cOglCmdInitOutputFb --------------------
890{
891 bool ok = m_pOutputFramebuffer->Init();
893 return ok;
894}
895
896//------------------ cOglCmdInitFb --------------------------
898{
899 bool ok = m_pFramebuffer->Init();
901 if (m_wait)
902 m_wait->Signal();
903 return ok;
904}
905
906//------------------ cOglCmdDeleteFb ------------------------
908{
910 if (m_pFramebuffer)
911 delete m_pFramebuffer;
912 return true;
913}
914
915//------------------ cOglCmdRenderFbToBufferFb --------------
917{
918 GLfloat x1 = m_x; // left
919 GLfloat y1 = m_y; // top
920 GLfloat x2 = m_x + m_pFramebuffer->ViewportWidth(); // right
921 GLfloat y2 = m_y + m_pFramebuffer->ViewportHeight(); // bottom
922
924 GLfloat texX2 = texX1 + 1.0f;
926 GLfloat texY2 = texY1 + 1.0f;
927
928 if (m_pFramebuffer->Scrollable()) {
934 }
935
937 // Pos // TexCoords
938 x1, y1, texX1, texY2, // left top
939 x1, y2, texX1, texY1, // left bottom
940 x2, y2, texX2, texY1, // right bottom
941
942 x1, y1, texX1, texY2, // left top
943 x2, y2, texX2, texY1, // right bottom
944 x2, y1, texX2, texY2 // right top
945 };
946
947 VertexBuffers[vbTexture]->ActivateShader();
948 VertexBuffers[vbTexture]->SetShaderAlpha(m_transparency);
949 VertexBuffers[vbTexture]->SetShaderProjectionMatrix(m_pBuffer->Width(), m_pBuffer->Height());
950 VertexBuffers[vbTexture]->SetShaderBorderColor(m_bcolor);
951
952 m_pBuffer->Bind();
954 return false;
955 if (!m_alphablending)
956 VertexBuffers[vbTexture]->DisableBlending();
957 VertexBuffers[vbTexture]->Bind();
960 VertexBuffers[vbTexture]->SetVertexSubData(quadVertices);
961 VertexBuffers[vbTexture]->DrawArrays();
963 VertexBuffers[vbTexture]->Unbind();
964
965 if (!m_alphablending)
966 VertexBuffers[vbTexture]->EnableBlending();
967 m_pBuffer->Unbind();
968
969 return true;
970}
971
972//------------------ cOglCmdCopyBufferToOutputFb ------------
974{
975 GLfloat x1 = m_x;
976 GLfloat y1 = m_y;
979
980 GLfloat texX1 = 0.0f;
981 GLfloat texX2 = 1.0f;
982 GLfloat texY1 = 1.0f;
983 GLfloat texY2 = 0.0f;
984
986 // Pos // TexCoords
987 x1, y1, texX1, texY1, //left top
988 x1, y2, texX1, texY2, //left bottom
989 x2, y2, texX2, texY2, //right bottom
990
991 x1, y1, texX1, texY1, //left top
992 x2, y2, texX2, texY2, //right bottom
993 x2, y1, texX2, texY1 //right top
994 };
995
996 VertexBuffers[vbTexture]->ActivateShader();
997 VertexBuffers[vbTexture]->SetShaderAlpha(255);
999 VertexBuffers[vbTexture]->SetShaderBorderColor(m_borderColor);
1000
1004 return false;
1005
1006 VertexBuffers[vbTexture]->Bind();
1007 VertexBuffers[vbTexture]->SetVertexSubData(quadVertices);
1008 VertexBuffers[vbTexture]->DrawArrays();
1009 VertexBuffers[vbTexture]->Unbind();
1010
1011 GL_CHECK(glFinish());
1012 // eglSwapBuffers and gbm_surface_lock_front_buffer in OsdDrawARGB()
1013 if (m_active)
1015 else
1017
1019
1020 return true;
1021}
1022
1023//------------------ cOglCmdFill ----------------------------
1025{
1026 glm::vec4 col;
1029 GL_CHECK(glClearColor(col.r, col.g, col.b, col.a));
1032
1033 return true;
1034}
1035
1036//------------------ cOglCmdBufferFill ----------------------
1038{
1039 glm::vec4 col;
1041 GL_CHECK(glClearColor(col.r, col.g, col.b, col.a));
1043
1044 return true;
1045}
1046
1047//------------------ cOglCmdDrawRectangle -------------------
1049{
1050 if (m_width <= 0 || m_height <= 0)
1051 return false;
1052
1053 GLfloat x1 = m_x;
1054 GLfloat y1 = m_y;
1055 GLfloat x2 = m_x + m_width;
1056 GLfloat y2 = m_y + m_height;
1057
1058 GLfloat vertices[] = {
1059 x1, y1, // left top
1060 x2, y1, // right top
1061 x2, y2, // right bottom
1062 x1, y2 // left bottom
1063 };
1064
1065 VertexBuffers[vbRect]->ActivateShader();
1066 VertexBuffers[vbRect]->SetShaderColor(m_color);
1067 VertexBuffers[vbRect]->SetShaderProjectionMatrix(m_pFramebuffer->Width(), m_pFramebuffer->Height());
1068
1070 VertexBuffers[vbRect]->DisableBlending();
1071 VertexBuffers[vbRect]->Bind();
1072 VertexBuffers[vbRect]->SetVertexSubData(vertices);
1073 VertexBuffers[vbRect]->DrawArrays();
1074 VertexBuffers[vbRect]->Unbind();
1075 VertexBuffers[vbRect]->EnableBlending();
1077
1078 return true;
1079}
1080
1081//------------------ cOglCmdDrawEllipse ---------------------
1082// quadrants:
1083// 0 draws the entire ellipse
1084// 1..4 draws only the first, second, third or fourth quadrant, respectively
1085// 5..8 draws the right, top, left or bottom half, respectively
1086// -1..-4 draws the inverted part of the given quadrant
1087//-----------------------------------------------------------
1089{
1090 if (m_width <= 0 || m_height <= 0)
1091 return false;
1092
1093 int numVertices = 0;
1095
1096 switch (m_quadrants) {
1097 case 0:
1099 break;
1100 case 1:
1101 case 2:
1102 case 3:
1103 case 4:
1104 case -1:
1105 case -2:
1106 case -3:
1107 case -4:
1109 break;
1110 case 5:
1111 case 6:
1112 case 7:
1113 case 8:
1115 break;
1116 default:
1117 break;
1118 }
1119
1120 VertexBuffers[vbEllipse]->ActivateShader();
1121 VertexBuffers[vbEllipse]->SetShaderColor(m_color);
1122 VertexBuffers[vbEllipse]->SetShaderProjectionMatrix(m_pFramebuffer->Width(), m_pFramebuffer->Height());
1123
1124 // not antialiased
1126 VertexBuffers[vbEllipse]->DisableBlending();
1127 VertexBuffers[vbEllipse]->Bind();
1128 VertexBuffers[vbEllipse]->SetVertexSubData(vertices, numVertices);
1129 VertexBuffers[vbEllipse]->DrawArrays(numVertices);
1130 VertexBuffers[vbEllipse]->Unbind();
1131 VertexBuffers[vbEllipse]->EnableBlending();
1133
1134 delete[] vertices;
1135 return true;
1136}
1137
1139{
1140 int size = 364;
1141 numVertices = size/2;
1144 GLfloat *vertices = new GLfloat[size];
1145 vertices[0] = m_x + radiusX;
1146 vertices[1] = m_y + radiusY;
1147 for (int i=0; i <= 180; i++) {
1148 vertices[2 * i + 2] = m_x + radiusX + (GLfloat)cos(2 * i * M_PI / 180.0f) * radiusX;
1149 vertices[2 * i + 3] = m_y + radiusY - (GLfloat)sin(2 * i * M_PI / 180.0f) * radiusY;
1150 }
1151 return vertices;
1152}
1153
1155{
1156 int size = 94;
1157 numVertices = size / 2;
1160 GLint transX = 0;
1161 GLint transY = 0;
1162 GLint startAngle = 0;
1163 GLfloat *vertices = new GLfloat[size];
1164 switch (m_quadrants) {
1165 case 1:
1166 vertices[0] = m_x;
1167 vertices[1] = m_y + m_height;
1168 transY = radiusY;
1169 break;
1170 case 2:
1171 vertices[0] = m_x + m_width;
1172 vertices[1] = m_y + m_height;
1173 transX = radiusX;
1174 transY = radiusY;
1175 startAngle = 90;
1176 break;
1177 case 3:
1178 vertices[0] = m_x + m_width;
1179 vertices[1] = m_y;
1180 transX = radiusX;
1181 startAngle = 180;
1182 break;
1183 case 4:
1184 vertices[0] = m_x;
1185 vertices[1] = m_y;
1186 startAngle = 270;
1187 break;
1188 case -1:
1189 vertices[0] = m_x + m_width;
1190 vertices[1] = m_y;
1191 transY = radiusY;
1192 break;
1193 case -2:
1194 vertices[0] = m_x;
1195 vertices[1] = m_y;
1196 transX = radiusX;
1197 transY = radiusY;
1198 startAngle = 90;
1199 break;
1200 case -3:
1201 vertices[0] = m_x;
1202 vertices[1] = m_y + m_height;
1203 transX = radiusX;
1204 startAngle = 180;
1205 break;
1206 case -4:
1207 vertices[0] = m_x + m_width;
1208 vertices[1] = m_y + m_height;
1209 startAngle = 270;
1210 break;
1211 default:
1212 break;
1213 }
1214 for (int i = 0; i <= 45; i++) {
1215 vertices[2 * i + 2] = m_x + transX + (GLfloat)cos((2 * i + startAngle) * M_PI / 180.0f) * radiusX;
1216 vertices[2 * i + 3] = m_y + transY - (GLfloat)sin((2 * i + startAngle) * M_PI / 180.0f) * radiusY;
1217 }
1218 return vertices;
1219}
1220
1222{
1223 int size = 184;
1224 numVertices = size / 2;
1225 GLfloat radiusX = 0.0f;
1226 GLfloat radiusY = 0.0f;
1227 GLint transX = 0;
1228 GLint transY = 0;
1229 GLint startAngle = 0;
1230 GLfloat *vertices = new GLfloat[size];
1231 switch (m_quadrants) {
1232 case 5:
1234 radiusY = (GLfloat)m_height / 2;
1235 vertices[0] = m_x;
1236 vertices[1] = m_y + radiusY;
1237 startAngle = 270;
1238 transY = radiusY;
1239 break;
1240 case 6:
1241 radiusX = (GLfloat)m_width / 2;
1243 vertices[0] = m_x + radiusX;
1244 vertices[1] = m_y + radiusY;
1245 startAngle = 0;
1246 transX = radiusX;
1247 transY = radiusY;
1248 break;
1249 case 7:
1251 radiusY = (GLfloat)m_height / 2;
1252 vertices[0] = m_x + radiusX;
1253 vertices[1] = m_y + radiusY;
1254 startAngle = 90;
1255 transX = radiusX;
1256 transY = radiusY;
1257 break;
1258 case 8:
1259 radiusX = (GLfloat)m_width / 2;
1261 vertices[0] = m_x + radiusX;
1262 vertices[1] = m_y;
1263 startAngle = 180;
1264 transX = radiusX;
1265 break;
1266 default:
1267 break;
1268 }
1269 for (int i=0; i <= 90; i++) {
1270 vertices[2 * i + 2] = m_x + transX + (GLfloat)cos((2 * i + startAngle) * M_PI / 180.0f) * radiusX;
1271 vertices[2 * i + 3] = m_y + transY - (GLfloat)sin((2 * i + startAngle) * M_PI / 180.0f) * radiusY;
1272 }
1273 return vertices;
1274}
1275
1276//------------------ cOglCmdDrawSlope -----------------------
1277// type:
1278// 0: horizontal, rising, lower
1279// 1: horizontal, rising, upper
1280// 2: horizontal, falling, lower
1281// 3: horizontal, falling, upper
1282// 4: vertical, rising, lower
1283// 5: vertical, rising, upper
1284// 6: vertical, falling, lower
1285// 7: vertical, falling, upper
1286//-----------------------------------------------------------
1288{
1289 if (m_width <= 0 || m_height <= 0)
1290 return false;
1291
1292 bool falling = m_type & 0x02;
1293 bool vertical = m_type & 0x04;
1294
1295 int steps = 100;
1296 if (m_width < 100)
1297 steps = 25;
1298 int numVertices = steps + 2;
1299 GLfloat *vertices = new GLfloat[numVertices * 2];
1300
1301 switch (m_type) {
1302 case 0:
1303 case 4:
1304 vertices[0] = (GLfloat)(m_x + m_width);
1305 vertices[1] = (GLfloat)(m_y + m_height);
1306 break;
1307 case 1:
1308 case 5:
1309 vertices[0] = (GLfloat)m_x;
1310 vertices[1] = (GLfloat)m_y;
1311 break;
1312 case 2:
1313 case 6:
1314 vertices[0] = (GLfloat)m_x;
1315 vertices[1] = (GLfloat)(m_y + m_height);
1316 break;
1317 case 3:
1318 case 7:
1319 vertices[0] = (GLfloat)(m_x + m_width);
1320 vertices[1] = (GLfloat)m_y;
1321 break;
1322 default:
1323 vertices[0] = (GLfloat)(m_x);
1324 vertices[1] = (GLfloat)(m_y);
1325 break;
1326 }
1327
1328 for (int i = 0; i <= steps; i++) {
1329 GLfloat c = cos(i * M_PI / steps);
1330 if (falling)
1331 c = -c;
1332 if (vertical) {
1333 vertices[2 * i + 2] = (GLfloat)m_x + (GLfloat)m_width / 2.0f + (GLfloat)m_width * c / 2.0f;
1334 vertices[2 * i + 3] = (GLfloat)m_y + (GLfloat)i * ((GLfloat)m_height) / steps ;
1335 } else {
1336 vertices[2 * i + 2] = (GLfloat)m_x + (GLfloat)i * ((GLfloat)m_width) / steps ;
1337 vertices[2 * i + 3] = (GLfloat)m_y + (GLfloat)m_height / 2.0f + (GLfloat)m_height * c / 2.0f;
1338 }
1339 }
1340
1341 VertexBuffers[vbSlope]->ActivateShader();
1342 VertexBuffers[vbSlope]->SetShaderColor(m_color);
1343 VertexBuffers[vbSlope]->SetShaderProjectionMatrix(m_pFramebuffer->Width(), m_pFramebuffer->Height());
1344
1345 // not antialiased
1347 VertexBuffers[vbSlope]->DisableBlending();
1348 VertexBuffers[vbSlope]->Bind();
1349 VertexBuffers[vbSlope]->SetVertexSubData(vertices, numVertices);
1350 VertexBuffers[vbSlope]->DrawArrays(numVertices);
1351 VertexBuffers[vbSlope]->Unbind();
1352 VertexBuffers[vbSlope]->EnableBlending();
1354
1355 delete[] vertices;
1356 return true;
1357}
1358
1359//------------------ cOglCmdDrawText ------------------------
1361{
1363 if (!f)
1364 return false;
1365
1366 if (!m_length)
1367 return false;
1368
1369 VertexBuffers[vbText]->ActivateShader();
1370 VertexBuffers[vbText]->SetShaderColor(m_colorText);
1371 VertexBuffers[vbText]->SetShaderProjectionMatrix(m_pFramebuffer->Width(), m_pFramebuffer->Height());
1372
1374 VertexBuffers[vbText]->Bind();
1375
1376 int xGlyph = m_x;
1377 int yGlyph = m_y;
1378 int fontHeight = f->Height();
1379 int bottom = f->Bottom();
1380 FT_ULong sym = 0;
1381 FT_ULong prevSym = 0;
1382 int kerning = 0;
1383
1384 // Check, if we only have symbols, which are in our atlas
1385 int unknown_char = 0;
1386 for (int i = 0; m_pSymbols[i]; i++) {
1387 if ((m_pSymbols[i] < MIN_CHARCODE) || (m_pSymbols[i] > MAX_CHARCODE)) {
1388 if (m_pSymbols[i]) {
1390 break;
1391 }
1392 }
1393 }
1394
1395 if (!unknown_char) {
1396 cOglFontAtlas *fa = f->Atlas();
1397 std::vector<GLfloat> vertices;
1398 vertices.reserve( 4 * 6 * m_length);
1399
1400 for (int i = 0; m_pSymbols[i]; i++) {
1401 sym = m_pSymbols[i];
1402
1404 // Get the glyph from the font atlas for ASCII code MIN_CHARCODE-MAX_CHARCODE
1405 g = fa->GetGlyph(sym);
1406
1407 if (!g) {
1408 LOGWARNING("openglosd: %s: could not load glyph %lx", __FUNCTION__, sym);
1409 continue;
1410 }
1411
1412 if ( m_limitX && xGlyph + g->AdvanceX() > m_limitX )
1413 break;
1414
1415 kerning = f->Kerning(g, prevSym);
1416 prevSym = sym;
1417
1418 GLfloat x2 = xGlyph + kerning + g->BearingLeft();
1419 GLfloat y2 = m_y + (fontHeight - bottom - g->BearingTop()); //top
1420 GLfloat w = g->Width();
1421 GLfloat h = g->Height();
1422
1423 vertices.push_back(x2);
1424 vertices.push_back(y2);
1425 vertices.push_back(g->OffsetX());
1426 vertices.push_back(g->OffsetY());
1427
1428 vertices.push_back(x2 + w);
1429 vertices.push_back(y2);
1430 vertices.push_back(g->OffsetX() + g->Width() / (float)fa->Width());
1431 vertices.push_back(g->OffsetY());
1432
1433 vertices.push_back(x2);
1434 vertices.push_back(y2 + h);
1435 vertices.push_back(g->OffsetX());
1436 vertices.push_back(g->OffsetY() + g->Height() / (float)fa->Height());
1437
1438 vertices.push_back(x2 + w);
1439 vertices.push_back(y2);
1440 vertices.push_back(g->OffsetX() + g->Width() / (float)fa->Width());
1441 vertices.push_back(g->OffsetY());
1442
1443 vertices.push_back(x2);
1444 vertices.push_back(y2 + h);
1445 vertices.push_back(g->OffsetX());
1446 vertices.push_back(g->OffsetY() + g->Height() / (float)fa->Height());
1447
1448 vertices.push_back(x2 + w);
1449 vertices.push_back(y2 + h);
1450 vertices.push_back(g->OffsetX() + g->Width() / (float)fa->Width());
1451 vertices.push_back(g->OffsetY() + g->Height() / (float)fa->Height());
1452
1453 xGlyph += kerning + g->AdvanceX();
1454 yGlyph += kerning + g->AdvanceY();
1455
1456
1457 if ( xGlyph > m_pFramebuffer->Width() - 1 )
1458 break;
1459 }
1460
1461 fa->BindTexture();
1462 VertexBuffers[vbText]->SetVertexData(vertices.data(), (vertices.size() / 4));
1463 VertexBuffers[vbText]->DrawArrays(vertices.size() / 4);
1464 } else {
1465 LOGDEBUG2(L_OPENGL, "openglosd: %s: char %d is not on the texture atlas, use single draw", __FUNCTION__, unknown_char);
1466 for (int i = 0; m_pSymbols[i]; i++) {
1467 sym = m_pSymbols[i];
1468 cOglGlyph *g = f->Glyph(sym);
1469 if (!g) {
1470 LOGWARNING("openglosd: %s: could not load glyph %lx", __FUNCTION__, sym);
1471 continue;
1472 }
1473
1474 if ( m_limitX && xGlyph + g->AdvanceX() > m_limitX )
1475 break;
1476
1477 kerning = f->Kerning(g, prevSym);
1478 prevSym = sym;
1479
1480 GLfloat x1 = xGlyph + kerning + g->BearingLeft(); // left
1481 GLfloat y1 = m_y + (fontHeight - bottom - g->BearingTop()); // top
1482 GLfloat x2 = x1 + g->Width(); // right
1483 GLfloat y2 = y1 + g->Height(); // bottom
1484
1485 GLfloat vertices[] = {
1486 x1, y2, 0.0, 1.0, // left bottom
1487 x1, y1, 0.0, 0.0, // left top
1488 x2, y1, 1.0, 0.0, // right top
1489
1490 x1, y2, 0.0, 1.0, // left bottom
1491 x2, y1, 1.0, 0.0, // right top
1492 x2, y2, 1.0, 1.0 // right bottom
1493 };
1494
1495 g->BindTexture();
1496 VertexBuffers[vbText]->SetVertexData(vertices);
1497 VertexBuffers[vbText]->DrawArrays();
1498
1499 xGlyph += kerning + g->AdvanceX();
1500
1501 if ( xGlyph > m_pFramebuffer->Width() - 1 )
1502 break;
1503 }
1504 }
1505
1507 VertexBuffers[vbText]->Unbind();
1509 return true;
1510}
1511
1512//------------------ cOglCmdDrawImage -----------------------
1514{
1515 if (m_width <= 0 || m_height <= 0)
1516 return false;
1517
1518 GLuint texture;
1519 GL_CHECK(glGenTextures(1, &texture));
1523 0,
1524 GL_RGBA,
1525 m_width,
1526 m_height,
1527 0,
1528 GL_RGBA,
1530 m_argb
1531 ));
1537
1538 GLfloat x1 = m_x; // left
1539 GLfloat y1 = m_y; // top
1540 GLfloat x2 = m_x + m_width * m_scaleX; // right
1541 GLfloat y2 = m_y + m_height * m_scaleY; // bottom
1542
1543 GLfloat quadVertices[] = {
1544 x1, y2, 0.0, 1.0, // left bottom
1545 x1, y1, 0.0, 0.0, // left top
1546 x2, y1, 1.0, 0.0, // right top
1547
1548 x1, y2, 0.0, 1.0, // left bottom
1549 x2, y1, 1.0, 0.0, // right top
1550 x2, y2, 1.0, 1.0 // right bottom
1551 };
1552
1553 VertexBuffers[vbTextureSwapBR]->ActivateShader();
1554 VertexBuffers[vbTextureSwapBR]->SetShaderAlpha(255);
1555 VertexBuffers[vbTextureSwapBR]->SetShaderProjectionMatrix(m_pFramebuffer->Width(), m_pFramebuffer->Height());
1556 VertexBuffers[vbTextureSwapBR]->SetShaderBorderColor(m_borderColor);
1557
1560 if (m_overlay)
1561 VertexBuffers[vbTextureSwapBR]->DisableBlending();
1563 VertexBuffers[vbTextureSwapBR]->SetVertexSubData(quadVertices);
1564 VertexBuffers[vbTextureSwapBR]->DrawArrays();
1565 VertexBuffers[vbTextureSwapBR]->Unbind();
1566 if (m_overlay)
1567 VertexBuffers[vbTextureSwapBR]->EnableBlending();
1570 GL_CHECK(glDeleteTextures(1, &texture));
1571
1572 return true;
1573}
1574
1575//------------------ cOglCmdDrawTexture ---------------------
1577{
1578 if (m_pImageRef->width <= 0 || m_pImageRef->height <= 0)
1579 return false;
1580
1581 GLfloat x1 = m_x; // top
1582 GLfloat y1 = m_y; // left
1583 GLfloat x2 = m_x + m_pImageRef->width * m_scaleX; // right
1584 GLfloat y2 = m_y + m_pImageRef->height * m_scaleY; // bottom
1585
1586 GLfloat quadVertices[] = {
1587 // Pos // TexCoords
1588 x1, y1, 0.0f, 0.0f, // left bottom
1589 x1, y2, 0.0f, 1.0f, // left top
1590 x2, y2, 1.0f, 1.0f, // right top
1591
1592 x1, y1, 0.0f, 0.0f, // left bottom
1593 x2, y2, 1.0f, 1.0f, // right top
1594 x2, y1, 1.0f, 0.0f // right bottom
1595 };
1596
1597 VertexBuffers[vbTextureSwapBR]->ActivateShader();
1598 VertexBuffers[vbTextureSwapBR]->SetShaderAlpha(255);
1599 VertexBuffers[vbTextureSwapBR]->SetShaderProjectionMatrix(m_pFramebuffer->Width(), m_pFramebuffer->Height());
1600 VertexBuffers[vbTextureSwapBR]->SetShaderBorderColor(m_borderColor);
1601
1605 VertexBuffers[vbTextureSwapBR]->SetVertexSubData(quadVertices);
1606 VertexBuffers[vbTextureSwapBR]->DrawArrays();
1607 VertexBuffers[vbTextureSwapBR]->Unbind();
1609
1610 return true;
1611}
1612
1613//------------------ cOglCmdStoreImage ----------------------
1635
1636//------------------ cOglCmdDropImage -----------------------
1638 if (m_pImageRef->texture != GL_NONE)
1640 m_pWait->Signal();
1641 return true;
1642}
1643
1644/******************************************************************************
1645 * cOglThread
1646 *****************************************************************************/
1648 : cThread("oglThread"),
1649 m_startWait(startWait),
1650 m_maxCacheSize(maxCacheSize * 1024 * 1024),
1651 m_pRender(device->Render())
1652{
1653 for (int i = 0; i < OGL_MAX_OSDIMAGES; i++) {
1654 m_imageCache[i].used = false;
1656 m_imageCache[i].width = 0;
1657 m_imageCache[i].height = 0;
1658 }
1659
1660 Start();
1661}
1662
1664{
1665 for (int i = 0; i < OGL_MAX_OSDIMAGES; i++) {
1666 if (m_imageCache[i].used) {
1668 }
1669 }
1670}
1671
1673{
1675 Cancel(-1);
1676}
1677
1679{
1681 Cancel(2);
1682 Cleanup();
1683 m_stalled = false;
1684}
1685
1687{
1688 while (m_stalled)
1689 cCondWait::SleepMs(10);
1690
1691 bool doSignal = false;
1692 Lock();
1693 if (m_commands.size() == 0)
1694 doSignal = true;
1695 m_commands.push(cmd);
1696 Unlock();
1697
1698 if (m_commands.size() > OGL_CMDQUEUE_SIZE) {
1699 m_stalled = true;
1700 }
1701
1702 if (doSignal || m_stalled)
1703 m_wait.Signal();
1704}
1705
1707{
1708 if (!m_maxCacheSize) {
1709 LOGERROR("openglosd: %s: cannot store image, no cache set", __FUNCTION__);
1710 return 0;
1711 }
1712
1713 if (image.Width() > m_maxTextureSize || image.Height() > m_maxTextureSize) {
1714 LOGERROR("openglosd: %s: cannot store image of %dpx x %dpx (maximum size is %dpx x %dpx) - falling back to cOsdProvider::StoreImageData()",
1716 return 0;
1717 }
1718
1719 int imgSize = image.Width() * image.Height();
1720 int newMemUsed = imgSize * sizeof(tColor) + m_memCached;
1721 if (newMemUsed > m_maxCacheSize) {
1722 float cachedMB = m_memCached / 1024.0f / 1024.0f;
1723 float maxMB = m_maxCacheSize / 1024.0f / 1024.0f;
1724 LOGERROR("openglosd: %s: Maximum size for GPU cache reached. Used: %.2fMB Max: %.2fMB", __FUNCTION__, cachedMB, maxMB);
1725 return 0;
1726 }
1727
1728 int slot = GetFreeSlot();
1729 if (!slot)
1730 return 0;
1731
1733 if (!argb) {
1734 LOGERROR("openglosd: %s: memory allocation of %d kb for OSD image failed", __FUNCTION__, (int)(imgSize * sizeof(tColor) / 1024));
1735 ClearSlot(slot);
1736 slot = 0;
1737 return 0;
1738 }
1739
1740 memcpy(argb, image.Data(), sizeof(tColor) * imgSize);
1741
1743 imageRef->width = image.Width();
1744 imageRef->height = image.Height();
1746
1747 cTimeMs timer(5000);
1748 while (imageRef->used && imageRef->texture == 0 && !timer.TimedOut())
1749 cCondWait::SleepMs(2);
1750
1751 if (imageRef->texture == GL_NONE) {
1752 LOGERROR("openglosd: %s: failed to store OSD image texture! (%s)", __FUNCTION__, timer.TimedOut() ? "timed out" : "allocation failed");
1754 slot = 0;
1755 }
1756
1757 m_memCached += imgSize * sizeof(tColor);
1758
1759 return slot;
1760}
1761
1763{
1764 Lock();
1765 int slot = 0;
1766 for (int i = 0; i < OGL_MAX_OSDIMAGES && !slot; i++) {
1767 if (!m_imageCache[i].used) {
1768 m_imageCache[i].used = true;
1769 slot = -i - 1;
1770 }
1771 }
1772 Unlock();
1773 return slot;
1774}
1775
1777{
1778 int i = -slot - 1;
1779 if (i >= 0 && i < OGL_MAX_OSDIMAGES) {
1780 Lock();
1781 m_imageCache[i].used = false;
1783 m_imageCache[i].width = 0;
1784 m_imageCache[i].height = 0;
1785 Unlock();
1786 }
1787}
1788
1790{
1791 int i = -slot - 1;
1792 if (0 <= i && i < OGL_MAX_OSDIMAGES)
1793 return &m_imageCache[i];
1794 return 0;
1795}
1796
1798{
1800 if (!imageRef)
1801 return;
1802 int imgSize = imageRef->width * imageRef->height * sizeof(tColor);
1806 dropWait.Wait();
1808}
1809
1811{
1812 if (!InitOpenGL()) {
1813 LOGERROR("openglosd: %s: Could not initiate OpenGL context", __FUNCTION__);
1814 Cleanup();
1815 m_startWait->Signal();
1816 return;
1817 }
1818
1819 if (!InitShaders()) {
1820 LOGERROR("openglosd: %s: Could not initiate shaders", __FUNCTION__);
1821 Cleanup();
1822 m_startWait->Signal();
1823 return;
1824 }
1825
1826 if (!InitVertexBuffers()) {
1827 LOGERROR("openglosd: %s: Vertex Buffers NOT initialized", __FUNCTION__);
1828 Cleanup();
1829 m_startWait->Signal();
1830 return;
1831 }
1832
1834 LOGDEBUG2(L_OPENGL, "openglosd: %s: Maximum Pixmap size: %dx%dpx", __FUNCTION__, m_maxTextureSize, m_maxTextureSize);
1835
1836 //now Thread is ready to do his job
1837 m_startWait->Signal();
1838 m_stalled = false;
1839
1840 LOGINFO("OpenGL context initialized");
1841
1842 uint64_t startFlush = 0;
1843 uint64_t endFlush = 0;
1844 bool timeReset = false;
1845
1846 while(Running()) {
1847 if (m_commands.empty()) {
1848 m_wait.Wait(20);
1849 continue;
1850 }
1851
1852 Lock();
1853 cOglCmd* cmd = m_commands.front();
1854 m_commands.pop();
1855 Unlock();
1856
1857 uint64_t start = cTimeMs::Now();
1858 if (strcmp(cmd->Description(), "InitFramebuffer") == 0 || timeReset) {
1859 startFlush = cTimeMs::Now();
1860 timeReset = false;
1861 }
1862
1863 { // start of locked context
1864 std::unique_lock<std::mutex> lock(m_mutex, std::defer_lock);
1865
1866 if (cmd->NeedsLockingAgainstStateChange())
1867 lock.lock();
1868
1869 if (!Running())
1870 continue;
1871
1872 cmd->Execute();
1873 } // end of locked context
1874
1875 LOGDEBUG2(L_OPENGL_TIME_ALL, "openglosd: %s: \"%-*s\", %dms, %d commands left, time %" PRIu64 "",
1876 __FUNCTION__, 15, cmd->Description(), (int)(cTimeMs::Now() - start), (int)(m_commands.size()), cTimeMs::Now());
1877
1878 if (strcmp(cmd->Description(), "Copy buffer to OutputFramebuffer") == 0) {
1879 endFlush = cTimeMs::Now();
1880 timeReset = true;
1881 LOGDEBUG2(L_OPENGL_TIME, "openglosd: %s: OSD Flush %dms, time %" PRIu64 "", __FUNCTION__, (int)(endFlush - startFlush), cTimeMs::Now());
1882 }
1883 delete cmd;
1884 if (m_stalled && m_commands.size() < OGL_CMDQUEUE_SIZE / 2)
1885 m_stalled = false;
1886 }
1887
1888 LOGINFO("OpenGL worker thread stopped");
1889}
1890
1895
1901{
1902 LOGDEBUG2(L_OPENGL, "openglosd: %s: Init OpenGL context", __FUNCTION__);
1903
1904 // Wait for the EGL context to be created
1905 while(!m_pRender || !m_pRender->GlInitiated()) {
1906 LOGDEBUG2(L_OPENGL, "openglosd: %s: wait for EGL context", __FUNCTION__);
1907 usleep(20000);
1908 }
1909
1910 eglAcquireContext(); // eglMakeCurrent with new eglSurface
1911
1912 GL_CHECK(LOGDEBUG2(L_OPENGL, " GL Version: \"%s\"", glGetString(GL_VERSION)));
1913 GL_CHECK(LOGDEBUG2(L_OPENGL, " GL Vendor: \"%s\"", glGetString(GL_VENDOR)));
1914 GL_CHECK(LOGDEBUG2(L_OPENGL, " GL Extensions: \"%s\"", glGetString(GL_EXTENSIONS)));
1915 GL_CHECK(LOGDEBUG2(L_OPENGL, " GL Renderer: \"%s\"", glGetString(GL_RENDERER)));
1916
1917 VertexBuffers[vbText]->EnableBlending();
1919 LOGDEBUG2(L_OPENGL, "openglosd: %s: Init OpenGL context done", __FUNCTION__);
1920
1921 return true;
1922}
1923
1925{
1926 for (int i = 0; i < stCount; i++) {
1927 cOglShader *shader = new cOglShader();
1928 if (!shader->Load((eShaderType)i))
1929 return false;
1930 Shaders[i] = shader;
1931 }
1932 LOGDEBUG2(L_OPENGL, "openglosd: %s: Shaders initialized", __FUNCTION__);
1933
1934 return true;
1935}
1936
1938{
1939 for (int i = 0; i < stCount; i++)
1940 delete Shaders[i];
1941}
1942
1944{
1945 for (int i = 0; i < vbCount; i++) {
1946 cOglVb *vb = new cOglVb(i);
1947 if (!vb->Init())
1948 return false;
1949 VertexBuffers[i] = vb;
1950 }
1951 LOGDEBUG2(L_OPENGL, "openglosd: %s: Vertex buffers initialized", __FUNCTION__);
1952
1953 return true;
1954}
1955
1957{
1958 for (int i=0; i < vbCount; i++) {
1959 delete VertexBuffers[i];
1960 }
1961}
1962
1964{
1965 LOGDEBUG2(L_OPENGL, "openglosd: %s: Cleaning up OpenGL stuff", __FUNCTION__);
1966
1970 DeleteShaders();
1972}
1973
1974/******************************************************************************
1975 * cOglPixmap
1976 *****************************************************************************/
1977cOglPixmap::cOglPixmap(std::shared_ptr<cOglThread> oglThread, int layer, const cRect &viewPort, const cRect &drawPort)
1978 : cPixmap(layer, viewPort, drawPort),
1979 m_pOglThread(oglThread)
1980{
1981 int width = drawPort.IsEmpty() ? viewPort.Width() : drawPort.Width();
1982 int height = drawPort.IsEmpty() ? viewPort.Height() : drawPort.Height();
1983
1984 if (width > m_pOglThread->MaxTextureSize() || height > m_pOglThread->MaxTextureSize()) {
1985 LOGWARNING("openglosd: %s: cannot allocate pixmap of %dpx x %dpx, clipped to %dpx x %dpx!", __FUNCTION__,
1986 width, height, std::min(width, m_pOglThread->MaxTextureSize()), std::min(height, m_pOglThread->MaxTextureSize()));
1987 width = std::min(width, m_pOglThread->MaxTextureSize());
1988 height = std::min(height, m_pOglThread->MaxTextureSize());
1989 }
1990
1991 m_pFramebuffer = new cOglFb(width, height, viewPort.Width(), viewPort.Height());
1992
1993#ifdef GRIDPOINTS
1994 // Creates a tiny font with height GRIDPOINTSTXTSIZE
1995 m_pTinyfont = cFont::CreateFont(Setup.FontOsd, GRIDPOINTSTXTSIZE);
1996#endif
1997}
1998
2000{
2001 if (!m_pOglThread->Active())
2002 return;
2003
2005#ifdef GRIDPOINTS
2006 delete m_pTinyfont;
2007#endif
2008}
2009
2011{
2012 cPixmap::MarkViewPortDirty(rect);
2013 SetDirty();
2014}
2015
2017{
2018 cPixmap::SetClean();
2019 SetDirty(false);
2020}
2021
2023{
2024 cPixmap::SetLayer(layer);
2025 SetDirty();
2026}
2027
2029{
2031 if (alpha != cPixmap::Alpha()) {
2032 cPixmap::SetAlpha(alpha);
2033 SetDirty();
2034 }
2035}
2036
2038{
2039 cPixmap::SetTile(tile);
2040 SetDirty();
2041}
2042
2044{
2045 cPixmap::SetViewPort(rect);
2046 SetDirty();
2047}
2048
2050{
2051 cPixmap::SetDrawPortPoint(point, dirty);
2052 if (dirty)
2053 SetDirty();
2054}
2055
2057{
2058 if (!m_pOglThread->Active())
2059 return;
2060
2063 SetDirty();
2065}
2066
2068{
2069 if (!m_pOglThread->Active())
2070 return;
2071
2074 SetDirty();
2076}
2077
2079{
2081}
2082
2087
2088void cOglPixmap::DrawScaledImage(const cPoint &point, const cImage &image, double factorX, double factorY, __attribute__ ((unused)) bool antiAlias)
2089{
2090 if (!m_pOglThread->Active())
2091 return;
2092
2093 tColor *argb = MALLOC(tColor, image.Width() * image.Height());
2094 if (!argb)
2095 return;
2096 memcpy(argb, image.Data(), sizeof(tColor) * image.Width() * image.Height());
2097
2098 m_pOglThread->DoCmd(new cOglCmdDrawImage(m_pFramebuffer, argb, image.Width(), image.Height(), point.X(), point.Y(), true, factorX, factorY));
2099#ifdef GRIDRECT
2101#endif
2102 SetDirty();
2103 MarkDrawPortDirty(cRect(point, cSize(image.Width() * factorX, image.Height() * factorY)).Intersected(DrawPort().Size()));
2104}
2105
2107{
2108 if (!m_pOglThread->Active())
2109 return;
2110
2112 sOglImage *img = m_pOglThread->GetImageRef(imageHandle);
2114#ifdef GRIDRECT
2116#endif
2117 SetDirty();
2118 MarkDrawPortDirty(cRect(point, cSize(img->width * factorX, img->height * factorY)).Intersected(DrawPort().Size()));
2119 }
2120}
2121
2123{
2124 cRect r(point.X(), point.Y(), 1, 1);
2125 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, r.X(), r.Y(), r.Width(), r.Height(), color));
2126#ifdef GRIDRECT
2128#endif
2129 SetDirty();
2131}
2132
2134{
2135 if (!m_pOglThread->Active())
2136 return;
2137
2139 bool specialColors = colorFg || colorBg;
2140 tColor *argb = MALLOC(tColor, bitmap.Width() * bitmap.Height());
2141 if (!argb)
2142 return;
2143
2144 tColor *p = argb;
2145 for (int py = 0; py < bitmap.Height(); py++)
2146 for (int px = 0; px < bitmap.Width(); px++) {
2147 tIndex index = *bitmap.Data(px, py);
2148 *p++ = (!index && overlay) ? clrTransparent :
2149 (specialColors ? (index == 0 ? colorBg : index == 1 ? colorFg :
2150 bitmap.Color(index)) : bitmap.Color(index));
2151 }
2152
2153 m_pOglThread->DoCmd(new cOglCmdDrawImage(m_pFramebuffer, argb, bitmap.Width(), bitmap.Height(), point.X(), point.Y(), true));
2154#ifdef GRIDRECT
2156#endif
2157
2158 SetDirty();
2159 MarkDrawPortDirty(cRect(cPoint(point.X(), point.Y()), cSize(bitmap.Width(), bitmap.Height())).Intersected(DrawPort().Size()));
2160}
2161
2162void cOglPixmap::DrawText(const cPoint &point, const char *s, tColor colorFg, tColor colorBg, const cFont *font, int width, int height, int alignment)
2163{
2164 DrawTextInternal(point, s, colorFg, colorBg, font, width, height, alignment, false);
2165}
2166
2167#ifdef GRIDPOINTS
2168void cOglPixmap::DrawGridText(const cPoint &point, const char *s, tColor colorFg, tColor colorBg, const cFont *font, int width, int height, int alignment)
2169{
2170 DrawTextInternal(point, s, colorFg, colorBg, font, width, height, alignment, true);
2171}
2172#endif
2173
2174void cOglPixmap::DrawTextInternal(const cPoint &point, const char *s, tColor colorFg, tColor colorBg, const cFont *font, int width, int height, int alignment, bool isGridText)
2175{
2176 if (!m_pOglThread->Active())
2177 return;
2178
2180 int len = s ? Utf8StrLen(s) : 0;
2181 unsigned int *symbols = MALLOC(unsigned int, len + 1);
2182 if (!symbols)
2183 return;
2184
2185 if (len)
2186 Utf8ToArray(s, symbols, len + 1);
2187 else
2188 symbols[0] = 0;
2189
2190 int x = point.X();
2191 int y = point.Y();
2192 int w = font->Width(s);
2193 int h = font->Height();
2194 int limitX = 0;
2195 int cw = width ? width : w;
2196 int ch = height ? height : h;
2197
2198 // workaround for messages in SkinElchiHD
2199 if (width > ViewPort().Width() && !x && !isGridText)
2200 x = ViewPort().Width() - w;
2201
2202 cRect r(x, y, cw, ch);
2203
2204 if (colorBg != clrTransparent)
2205 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, r.X(), r.Y(), r.Width(), r.Height(), colorBg));
2206
2207 if (width || height)
2208 limitX = x + cw;
2209
2210 if (width) {
2211 if ((alignment & taLeft) != 0) {
2212 if ((alignment & taBorder) != 0)
2213 x += std::max(h / TEXT_ALIGN_BORDER, 1);
2214 } else if ((alignment & taRight) != 0) {
2215 if (w < width)
2216 x += width - w;
2217 if ((alignment & taBorder) != 0)
2218 x -= std::max(h / TEXT_ALIGN_BORDER, 1);
2219 } else { // taCentered
2220 if (w < width)
2221 x += (width - w) / 2;
2222 }
2223 }
2224
2225 if (height) {
2226 if ((alignment & taTop) != 0)
2227 ;
2228 else if ((alignment & taBottom) != 0) {
2229 if (h < height)
2230 y += height - h;
2231 } else { // taCentered
2232 if (h < height)
2233 y += (height - h) / 2;
2234 }
2235 }
2236
2237 m_pOglThread->DoCmd(new cOglCmdDrawText(m_pFramebuffer, x, y, symbols, limitX, font->FontName(), font->Size(), colorFg, len));
2238
2239#ifdef GRIDTEXT
2240 if (!isGridText)
2242#endif
2243
2244 SetDirty();
2246}
2247
2249{
2250 if (!m_pOglThread->Active())
2251 return;
2252
2254 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, rect.X(), rect.Y(), rect.Width(), rect.Height(), color));
2255#ifdef GRIDRECT
2257#endif
2258
2259 SetDirty();
2261}
2262
2264{
2265 if (!m_pOglThread->Active())
2266 return;
2267
2269 m_pOglThread->DoCmd(new cOglCmdDrawEllipse(m_pFramebuffer, rect.X(), rect.Y(), rect.Width(), rect.Height(), color, quadrants));
2270#ifdef GRIDRECT
2272#endif
2273
2274 SetDirty();
2276}
2277
2279{
2280 if (!m_pOglThread->Active())
2281 return;
2282
2284 m_pOglThread->DoCmd(new cOglCmdDrawSlope(m_pFramebuffer, rect.X(), rect.Y(), rect.Width(), rect.Height(), color, type));
2285#ifdef GRIDRECT
2287#endif
2288
2289 SetDirty();
2291}
2292
2293void cOglPixmap::Render(const cPixmap *pixmap, const cRect &source, const cPoint &dest)
2294{
2295 LOGWARNING("openglosd: %s: %d %d %d not implemented in OpenGl OSD", __FUNCTION__, pixmap->ViewPort().X(), source.X(), dest.X());
2296}
2297
2298void cOglPixmap::Copy(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
2304{
2305 LOGWARNING("openglosd: %s: %d %d not implemented in OpenGl OSD", __FUNCTION__, 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
2313#ifdef GRIDPOINTS
2314void cOglPixmap::DrawGridRect(const cRect &rect, int offset, int size, tColor clr, tColor bg, const cFont *font)
2315{
2316 int x1 = rect.X() + offset;
2317 int x2 = rect.X() + rect.Width() + offset;
2318 int y1 = rect.Y();
2319 int y2 = rect.Y() + rect.Height();
2320 char p1[10];
2321 char p2[10];
2322 char p3[10];
2323 char p4[10];
2324 sprintf(p1, "%d.%d", x1, y1);
2325 sprintf(p2, "%d.%d", x2, y1);
2326 sprintf(p3, "%d.%d", x1, y2);
2327 sprintf(p4, "%d.%d", x2, y2);
2328
2329 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, x1, y1, size, size, clr));
2330#ifdef GRIDPOINTSTEXT
2332#endif
2333 if (Rect.Width() && Rect.Height()) {
2334 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, x2, y1, size, size, clr));
2335 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, x1, y2, size, size, clr));
2336 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, x2, y2, size, size, clr));
2337#ifdef GRIDPOINTSTEXT
2341#endif
2342 }
2343}
2344#endif
2345
2346/******************************************************************************
2347 * cOglOsd
2348 *****************************************************************************/
2350
2351cOglOsd::cOglOsd(int left, int top, uint level, std::shared_ptr<cOglThread> oglThread, cSoftHdDevice *device)
2352 : cOsd(left, top, level),
2353 m_pOglThread(oglThread),
2354 m_isSubtitleOsd(level == 10 ? true : false),
2355 m_pDevice(device)
2356{
2357 int osdWidth = 0;
2358 int osdHeight = 0;
2359 double pixelAspect;
2361 LOGDEBUG2(L_OSD, "openglosd: %s: New Osd %p osdLeft %d osdTop %d screenWidth %d screenHeight %d", __FUNCTION__, this, left, top, osdWidth, osdHeight);
2362
2363 m_maxPixmapSize.Set(m_pOglThread->MaxTextureSize(), m_pOglThread->MaxTextureSize());
2364
2365 if (!OutputFramebuffer) {
2368 }
2369}
2370
2372{
2373 if (!m_pOglThread->Active() || !Active() || !m_pBufferFramebuffer)
2374 return;
2375
2376 LOGDEBUG2(L_OSD, "openglosd: %s: Delete Osd %p", __FUNCTION__, this);
2378
2379 SetActive(false); // OsdClose() is done in cOglCmdCopyBufferToOutputFb()
2382}
2383
2385{
2386 cRect r;
2387 if (numAreas > 1)
2388 m_isSubtitleOsd = true;
2389 for (int i = 0; i < numAreas; i++)
2390 r.Combine(cRect(areas[i].x1, areas[i].y1, areas[i].Width(), areas[i].Height()));
2391
2392 tArea area = { r.Left(), r.Top(), r.Right(), r.Bottom(), 32 };
2393
2394 // now we know the actual osd size, create double buffer frame buffer
2398 }
2399 m_pBufferFramebuffer = new cOglFb(r.Width(), r.Height(), r.Width(), r.Height());
2402 initiated.Wait();
2403
2404 return cOsd::SetAreas(&area, 1);
2405}
2406
2408{
2409 if (!m_pOglThread->Active())
2410 return NULL;
2411
2414 if (cOsd::AddPixmap(p)) {
2415 // find a free slot
2416 for (int i = 0; i < m_pOglPixmaps.Size(); i++) {
2417 if (!m_pOglPixmaps[i])
2418 return m_pOglPixmaps[i] = p;
2419 }
2420 m_pOglPixmaps.Append(p);
2421 return p;
2422 }
2423 delete p;
2424
2425 return NULL;
2426}
2427
2429{
2430 if (!m_pOglThread->Active())
2431 return;
2432 if (!Pixmap)
2433 return;
2434
2436 int start = 1;
2437 if (m_isSubtitleOsd)
2438 start = 0;
2439 for (int i = start; i < m_pOglPixmaps.Size(); i++) {
2440 if (m_pOglPixmaps[i] == Pixmap) {
2441 if (Pixmap->Layer() >= 0)
2442 m_pOglPixmaps[0]->MarkViewPortDirty(m_pOglPixmaps[i]->ViewPort());
2443
2444 m_pOglPixmaps[i] = NULL;
2445 if (i)
2446 cOsd::DestroyPixmap(Pixmap);
2447
2448 return;
2449 }
2450 }
2451}
2452
2454{
2455 if (!m_pOglThread->Active() || !Active())
2456 return;
2457
2458 LOGDEBUG2(L_OSD, "openglosd: %s: Flush Osd %p", __FUNCTION__, this);
2460 // check for dirty areas
2461 m_pDirtyViewport.Set(0, 0, 0, 0);
2462 for (int i = 0; i < m_pOglPixmaps.Size(); i++) {
2463 if (m_pOglPixmaps[i] && m_pOglPixmaps[i]->IsDirty()) {
2464 if (m_isSubtitleOsd)
2465 m_pDirtyViewport.Combine(m_pOglPixmaps[i]->DirtyViewPort().Size());
2466 else
2468
2469 m_pOglPixmaps[i]->SetClean();
2470 }
2471 }
2472
2473 if (m_pDirtyViewport.IsEmpty())
2474 return;
2475
2476 // clear private buffer within the dirty area
2478 m_pDirtyViewport.X(),
2479 m_pDirtyViewport.Y(),
2480 m_pDirtyViewport.Width(),
2481 m_pDirtyViewport.Height(),
2483
2484 // render pixmap textures blended to private buffer
2485 for (int layer = 0; layer < MAXPIXMAPLAYERS; layer++) {
2486 for (int i = 0; i < m_pOglPixmaps.Size(); i++) {
2487 if (!m_pOglPixmaps[i])
2488 continue;
2489
2490 if (m_pOglPixmaps[i]->Layer () != layer)
2491 continue;
2492
2493 if (m_isSubtitleOsd && !m_pDirtyViewport.Intersects(m_pOglPixmaps[i]->ViewPort().Size()))
2494 continue;
2495
2496 if (!m_isSubtitleOsd && !m_pDirtyViewport.Intersects(m_pOglPixmaps[i]->ViewPort()))
2497 continue;
2498
2499 bool alphablending = layer == 0 ? false : true; // decide wether to render (with alpha) or copy a pixmap
2500 m_pOglThread->DoCmd(new cOglCmdRenderFbToBufferFb(m_pOglPixmaps[i]->Framebuffer(),
2502 m_isSubtitleOsd ? 0 : m_pOglPixmaps[i]->ViewPort().X(),
2503 m_isSubtitleOsd ? 0 : m_pOglPixmaps[i]->ViewPort().Y(),
2504 m_pOglPixmaps[i]->Alpha(),
2505 m_pOglPixmaps[i]->DrawPort().X(),
2506 m_pOglPixmaps[i]->DrawPort().Y(),
2507 m_pDirtyViewport.X(),
2508 m_pDirtyViewport.Top(),
2509 m_pDirtyViewport.Width(),
2510 m_pDirtyViewport.Height(),
2511 alphablending));
2512 }
2513 }
2514 // copy the private buffer to output framebuffer
2516
2518 Left() + (m_isSubtitleOsd ? m_pOglPixmaps[0]->ViewPort().X() : 0),
2519 Top() + (m_isSubtitleOsd ? m_pOglPixmaps[0]->ViewPort().Y() : 0), 1, m_pDevice));
2520}
2521
2522void cOglOsd::DrawScaledBitmap(int x, int y, const cBitmap &Bitmap, double FactorX, double FactorY, bool AntiAlias)
2523{
2524 if (!m_pOglPixmaps[0])
2525 return;
2526
2527 std::unique_ptr<cBitmap> scaledBitmap;
2528 const cBitmap *b = &Bitmap;
2529
2530 if (!DoubleEqual(FactorX, 1.0) || !DoubleEqual(FactorY, 1.0)) {
2531 scaledBitmap.reset(Bitmap.Scaled(FactorX, FactorY, AntiAlias));
2532 b = scaledBitmap.get();
2533 }
2534
2535 int xNew = x;
2536 int yNew = y;
2537
2538 const cRect &viewport = m_pOglPixmaps[0]->ViewPort();
2539 if (m_isSubtitleOsd && (x >= viewport.X()))
2540 xNew -= viewport.X();
2541 if (m_isSubtitleOsd && (y >= viewport.Y()))
2542 yNew -= viewport.Y();
2543
2544 m_pOglPixmaps[0]->DrawBitmap(cPoint(xNew, yNew), *b);
2545}
2546
Glyph on a Texture Atlas.
Definition openglosd.h:139
cOglOutputFb * m_pOutputFramebuffer
Definition openglosd.h:412
cSoftHdDevice * m_pDevice
Definition openglosd.h:416
tColor * m_argb
Definition openglosd.h:547
cString m_fontName
Definition openglosd.h:525
unsigned int * m_pSymbols
Definition openglosd.h:527
sOglImage * m_pImageRef
Definition openglosd.h:568
sOglImage * m_pImageRef
Definition openglosd.h:598
cCondWait * m_pWait
Definition openglosd.h:599
GLint m_color
Definition openglosd.h:428
cCondWait * m_wait
Definition openglosd.h:353
cOglOutputFb * m_pOutputFramebuffer
Definition openglosd.h:341
sOglImage * m_pImageRef
Definition openglosd.h:584
OpenGL Hardware Command.
Definition openglosd.h:320
cOglFb * m_pFramebuffer
Definition openglosd.h:329
OpenGL Framebuffer/ Texture Object.
Definition openglosd.h:225
GLint m_width
Definition openglosd.h:243
GLuint m_framebuffer
Definition openglosd.h:245
GLint ViewportHeight(void)
Definition openglosd.h:240
GLuint m_texture
Definition openglosd.h:246
GLint m_viewPortWidth
Definition openglosd.h:247
GLint Height(void)
Definition openglosd.h:237
GLint ViewportWidth(void)
Definition openglosd.h:239
GLint Width(void)
Definition openglosd.h:236
bool m_scrollable
Definition openglosd.h:248
bool Scrollable(void)
Definition openglosd.h:238
GLint m_height
Definition openglosd.h:243
GLint m_viewPortHeight
Definition openglosd.h:247
bool m_initiated
Definition openglosd.h:242
Texture Atlas for a Font.
Definition openglosd.h:171
GLuint m_texture
Definition openglosd.h:180
cOglAtlasGlyph * m_pGlyph[MAX_CHARCODE - MIN_CHARCODE+1]
Definition openglosd.h:183
OpenGL Representation of a VDR Font.
Definition openglosd.h:191
int Height(void)
Definition openglosd.h:200
int m_size
Definition openglosd.h:209
cString m_name
Definition openglosd.h:208
cOglFontAtlas * Atlas(void)
Definition openglosd.h:195
int Bottom(void)
Definition openglosd.h:199
FT_Face m_face
Definition openglosd.h:212
cOglFontAtlas * m_pAtlas
Definition openglosd.h:214
cList< cOglGlyph > m_glyphCache
Definition openglosd.h:213
int m_bottom
Definition openglosd.h:211
int m_height
Definition openglosd.h:210
Single Glyph of a Font.
Definition openglosd.h:98
GLuint m_texture
Definition openglosd.h:131
unsigned char * m_pBuffer
Definition openglosd.h:128
int m_height
Definition openglosd.h:127
cVector< tKerning > m_pKerningCache
Definition openglosd.h:130
int m_width
Definition openglosd.h:126
std::shared_ptr< cOglThread > m_pOglThread
pointer to thread, which executes the commands
Definition openglosd.h:725
bool m_isSubtitleOsd
true, if this is a subtitle osd
Definition openglosd.h:727
cSoftHdDevice * m_pDevice
pointer to cSofthdDevice
Definition openglosd.h:730
cOglFb * m_pBufferFramebuffer
all pixmaps are composed onto this framebuffer after each other, before this one is blit onto the OSD...
Definition openglosd.h:723
cRect m_pDirtyViewport
the dirty viewport
Definition openglosd.h:729
cVector< cOglPixmap * > m_pOglPixmaps
array of pixmaps
Definition openglosd.h:726
cSize m_maxPixmapSize
maximum allowed size of a pixmap (depends on the maximum OpenGL texture size)
Definition openglosd.h:728
Main Framebuffer/ Texture Object for OSD.
Definition openglosd.h:256
GLuint m_framebuffer
Definition openglosd.h:263
GLuint m_texture
Definition openglosd.h:264
OpenGL Implementation of a cPixmap.
Definition openglosd.h:660
cOglFb * m_pFramebuffer
everything is drawn onto this framebuffer (one per pixmap)
Definition openglosd.h:694
std::shared_ptr< cOglThread > m_pOglThread
Definition openglosd.h:695
virtual void SetDirty(bool dirty=true)
Definition openglosd.h:669
virtual void DrawScaledImage(const cPoint &, const cImage &, double FactorX=1.0f, double FactorY=1.0f, bool AntiAlias=false)
Vertex/Fragment Shader.
Definition openglosd.h:74
GLuint m_id
Definition openglosd.h:89
eShaderType m_type
Definition openglosd.h:88
long m_memCached
Definition openglosd.h:640
long m_maxCacheSize
Definition openglosd.h:641
bool m_stalled
Definition openglosd.h:636
sOglImage m_imageCache[OGL_MAX_OSDIMAGES]
Definition openglosd.h:639
cCondWait * m_startWait
Definition openglosd.h:634
cCondWait m_wait
Definition openglosd.h:635
cVideoRender * m_pRender
Definition openglosd.h:642
std::mutex m_mutex
Definition openglosd.h:643
GLint m_maxTextureSize
Definition openglosd.h:638
std::queue< cOglCmd * > m_commands
Definition openglosd.h:637
Vertex Buffers.
Definition openglosd.h:282
int m_sizeVertex2
Definition openglosd.h:309
GLuint m_positionLoc
Definition openglosd.h:306
eVertexBufferType m_type
Definition openglosd.h:302
int m_sizeVertex1
Definition openglosd.h:308
int m_numVertices
Definition openglosd.h:310
eShaderType m_shader
Definition openglosd.h:303
GLuint m_texCoordsLoc
Definition openglosd.h:307
GLuint m_vbo
Definition openglosd.h:305
GLuint m_drawMode
Definition openglosd.h:311
Output Device Implementation.
EGLSurface EglSurface(void)
EGLDisplay EglDisplay(void)
EGLContext EglContext(void)
int GlInitiated(void)
void OsdDrawARGB(int, int, int, int, int, const uint8_t *, int, int)
Draw an OSD pixmap.
virtual void GetOsdSize(int &, int &, double &)
Returns the width, height and aspect ratio the OSD.
void OsdClose(void)
Close the OSD.
__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:42
#define LOGERROR
log to LOG_ERR
Definition logger.h:34
#define GL_CHECK(stmt)
glCheckError macro
Definition misc.h:56
#define LOGWARNING
log to LOG_WARN
Definition logger.h:36
#define LOGINFO
log to LOG_INFO
Definition logger.h:38
#define EGL_CHECK(stmt)
eglCheckError macro
Definition misc.h:62
@ L_OPENGL_TIME
opengl osd flush time measurement
Definition logger.h:61
@ L_OSD
osd logs
Definition logger.h:54
@ L_OPENGL
opengl osd logs
Definition logger.h:60
@ L_OPENGL_TIME_ALL
opengl osd all commands time measurement
Definition logger.h:62
virtual ~cOglOsd()
void DoCmd(cOglCmd *)
void BindTexture(void)
virtual bool Execute(void)
#define OGL_MAX_OSDIMAGES
Definition openglosd.h:602
static void Cleanup(void)
virtual void Unbind(void)
virtual void Clear(void)
cOglFont(const char *, int)
bool CheckCompileErrors(GLuint, bool program=false)
virtual void SetClean(void)
void EnableBlending(void)
virtual void Unbind(void)
virtual bool Execute(void)
virtual bool Execute(void)
cOglGlyph * Glyph(FT_ULong) const
virtual void DrawRectangle(const cRect &, tColor)
static cOglOutputFb * OutputFramebuffer
main OSD output framebuffer - this keeps our finished "OSD" (one per OSD)
Definition openglosd.h:721
static void Init(void)
bool InitOpenGL(void)
bool InitVertexBuffers(void)
#define MIN_CHARCODE
Definition openglosd.h:156
virtual bool Execute(void)
virtual void Pan(const cPoint &, const cRect &Source=cRect::Null)
virtual bool Execute(void)
virtual bool Execute(void)
cOglGlyph(FT_ULong, FT_BitmapGlyph)
void CleanupImageCache(void)
void LoadTexture(void)
void SetMatrix4(const GLchar *, const glm::mat4 &)
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)
eShaderType
Definition openglosd.h:61
virtual void DrawImage(const cPoint &, const cImage &)
void SetVector4f(const GLchar *, GLfloat, GLfloat, GLfloat, GLfloat)
virtual ~cOglPixmap(void)
void Bind(void)
cOglFontAtlas(FT_Face, int)
int GetFreeSlot(void)
static cOglFont * Get(const char *, int)
virtual void Flush(void)
const char * textureFragmentShaderSwapBR
Texture Fragment Shader (swapped blue/red)
void Use(void)
Definition openglosd.cpp:78
cOglFb(GLint, GLint, GLint, GLint)
GLfloat * CreateVerticesFull(int &)
virtual ~cOglFont(void)
GLfloat * CreateVerticesHalf(int &)
virtual bool Execute(void)
GLfloat * CreateVerticesQuadrant(int &)
void SetFloat(const GLchar *, GLfloat)
void SetKerningCache(FT_ULong, int)
void SetInteger(const GLchar *, GLint)
void SetShaderColor(GLint)
virtual eOsdError SetAreas(const tArea *, int)
void Stop(void)
const char * rectVertexShader
Rectangle Vertex Shader.
cOglPixmap(std::shared_ptr< cOglThread >, int, const cRect &, const cRect &DrawPort=cRect::Null)
bool InitShaders(void)
int Kerning(cOglGlyph *glyph, FT_ULong prevSym) const
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)
static cOglVb * VertexBuffers[vbCount]
virtual ~cOglFb(void)
void SetShaderTexture(GLint)
virtual bool Execute(void)
void DisableBlending(void)
#define MAX_CHARCODE
Definition openglosd.h:157
void SetVertexSubData(GLfloat *, int count=0)
virtual ~cOglGlyph()
virtual void SetTile(bool)
const char * textureFragmentShader
Texture Fragment Shader.
cOglThread(cCondWait *startWait, int maxCacheSize, cSoftHdDevice *device)
void SetVector3f(const GLchar *, GLfloat, GLfloat, GLfloat)
const char * rectFragmentShader
Rectangle Fragment Shader.
const char * textFragmentShader
Text Fragment Shader.
void Bind(void)
virtual void DrawScaledBitmap(int, int, const cBitmap &, double, double, bool AntiAlias=false)
void SetShaderProjectionMatrix(GLint, GLint)
virtual bool Execute(void)
virtual void MarkViewPortDirty(const cRect &)
virtual void Scroll(const cPoint &, const cRect &Source=cRect::Null)
bool Load(eShaderType)
Definition openglosd.cpp:83
void SetVertexData(GLfloat *, int count=0)
static void ConvertColor(const GLint &colARGB, glm::vec4 &col)
Definition openglosd.cpp:66
virtual bool Execute(void)
void DropImageData(int)
cOglAtlasGlyph * GetGlyph(int) const
void Cleanup(void)
const char * textureVertexShader
Texture Vertex Shader.
#define KERNING_UNKNOWN
void DeleteShaders(void)
virtual bool Execute(void)
void DrawArrays(int count=0)
virtual void Action(void)
virtual ~cOglFontAtlas(void)
static cOglShader * Shaders[stCount]
Definition openglosd.cpp:76
void ActivateShader(void)
virtual bool Init(void)
void ClearSlot(int slot)
bool BindTexture(void)
virtual bool Execute(void)
void RequestStop(void)
int StoreImage(const cImage &)
bool Compile(const char *, const char *)
virtual cPixmap * CreatePixmap(int, const cRect &, const cRect &DrawPort=cRect::Null)
const char * textVertexShader
Text Vertex Shader.
virtual void SetLayer(int)
void SetVector2f(const GLchar *, GLfloat, GLfloat)
#define OGL_CMDQUEUE_SIZE
Definition openglosd.h:603
virtual void Fill(tColor)
sOglImage * GetImageRef(int)
void SetShaderAlpha(GLint)
int GetKerningCache(FT_ULong)
cOglOsd(int, int, uint, std::shared_ptr< cOglThread >, cSoftHdDevice *)
virtual bool Execute(void)
static bool s_initiated
Definition openglosd.h:204
bool Init(void)
virtual void SetDrawPortPoint(const cPoint &, bool Dirty=true)
virtual void DrawBitmap(const cPoint &, const cBitmap &, tColor ColorFg=0, tColor ColorBg=0, bool Overlay=false)
static FT_Library s_ftLib
Definition openglosd.h:205
void DeleteVertexBuffers(void)
void BindTexture(void)
void Unbind(void)
virtual bool Init(void)
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 SetViewPort(const cRect &)
virtual bool Execute(void)
void SetShaderBorderColor(GLint)
virtual void DestroyPixmap(cPixmap *)
void eglAcquireContext(void)
static cList< cOglFont > * s_pFonts
Definition openglosd.h:206
virtual bool Execute(void)
@ stText
Definition openglosd.h:65
@ stCount
Definition openglosd.h:66
@ stTextureSwapBR
Definition openglosd.h:64
@ stRect
Definition openglosd.h:62
@ stTexture
Definition openglosd.h:63
@ vbSlope
Definition openglosd.h:270
@ vbCount
Definition openglosd.h:274
@ vbText
Definition openglosd.h:273
@ vbTexture
Definition openglosd.h:271
@ vbEllipse
Definition openglosd.h:269
@ vbRect
Definition openglosd.h:268
@ vbTextureSwapBR
Definition openglosd.h:272
Logger Header File.
Misc Functions.
OpenGL OSD Header File.
const char * message
Definition openglosd.h:34
const struct @0 FT_Errors[]
int code
Definition openglosd.h:33
Shader Definitions for OpenGL OSD.
Output Device Header File.
GLint height
Definition openglosd.h:57
bool used
Definition openglosd.h:58
GLint width
Definition openglosd.h:56
GLuint texture
Definition openglosd.h:55
Video Renderer (Display) Header File.