1 /*****************************************************************************
2 * vout_helper.c: OpenGL and OpenGL ES output common code
3 *****************************************************************************
4 * Copyright (C) 2004-2016 VLC authors and VideoLAN
5 * Copyright (C) 2009, 2011 Laurent Aimar
7 * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
8 * Ilkka Ollakka <ileoo@videolan.org>
10 * Adrien Maglo <magsoft at videolan dot org>
11 * Felix Paul Kühne <fkuehne at videolan dot org>
12 * Pierre d'Herbemont <pdherbemont at videolan dot org>
14 * This program is free software; you can redistribute it and/or modify it
15 * under the terms of the GNU Lesser General Public License as published by
16 * the Free Software Foundation; either version 2.1 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public License
25 * along with this program; if not, write to the Free Software Foundation,
26 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
27 *****************************************************************************/
35 #include <vlc_common.h>
36 #include <vlc_subpicture.h>
37 #include <vlc_opengl.h>
38 #include <vlc_modules.h>
40 #include <vlc_viewpoint.h>
43 #include "vout_helper.h"
45 #include "sub_renderer.h"
47 #define SPHERE_RADIUS 1.f
52 struct vlc_gl_renderer
*renderer
;
55 GLfloat OrientationMatrix
[16];
56 GLfloat ProjectionMatrix
[16];
57 GLfloat ZoomMatrix
[16];
58 GLfloat ViewMatrix
[16];
61 struct { /* UniformLocation */
62 GLint TransformMatrix
;
63 GLint OrientationMatrix
;
64 GLint ProjectionMatrix
;
68 struct { /* AttribLocation */
69 GLint MultiTexCoord
[3];
74 struct vout_display_opengl_t
{
81 GLsizei tex_width
[PICTURE_PLANE_MAX
];
82 GLsizei tex_height
[PICTURE_PLANE_MAX
];
84 GLuint texture
[PICTURE_PLANE_MAX
];
89 GLuint vertex_buffer_object
;
90 GLuint index_buffer_object
;
91 GLuint texture_buffer_object
[PICTURE_PLANE_MAX
];
94 unsigned int i_x_offset
;
95 unsigned int i_y_offset
;
96 unsigned int i_visible_width
;
97 unsigned int i_visible_height
;
105 float f_fovx
; /* f_fovx and f_fovy are linked but we keep both */
106 float f_fovy
; /* to avoid recalculating them when needed. */
107 float f_z
; /* Position of the camera on the shpere radius vector */
110 struct vlc_gl_sub_renderer
*sub_renderer
;
113 static const vlc_fourcc_t gl_subpicture_chromas
[] = {
118 static const GLfloat identity
[] = {
119 1.0f
, 0.0f
, 0.0f
, 0.0f
,
120 0.0f
, 1.0f
, 0.0f
, 0.0f
,
121 0.0f
, 0.0f
, 1.0f
, 0.0f
,
122 0.0f
, 0.0f
, 0.0f
, 1.0f
125 static void getZoomMatrix(float zoom
, GLfloat matrix
[static 16]) {
127 const GLfloat m
[] = {
129 1.0f
, 0.0f
, 0.0f
, 0.0f
,
130 0.0f
, 1.0f
, 0.0f
, 0.0f
,
131 0.0f
, 0.0f
, 1.0f
, 0.0f
,
132 0.0f
, 0.0f
, zoom
, 1.0f
135 memcpy(matrix
, m
, sizeof(m
));
138 /* perspective matrix see https://www.opengl.org/sdk/docs/man2/xhtml/gluPerspective.xml */
139 static void getProjectionMatrix(float sar
, float fovy
, GLfloat matrix
[static 16]) {
144 float f
= 1.f
/ tanf(fovy
/ 2.f
);
146 const GLfloat m
[] = {
147 f
/ sar
, 0.f
, 0.f
, 0.f
,
149 0.f
, 0.f
, (zNear
+ zFar
) / (zNear
- zFar
), -1.f
,
150 0.f
, 0.f
, (2 * zNear
* zFar
) / (zNear
- zFar
), 0.f
};
152 memcpy(matrix
, m
, sizeof(m
));
155 static void getViewpointMatrixes(vout_display_opengl_t
*vgl
,
156 video_projection_mode_t projection_mode
,
159 if (projection_mode
== PROJECTION_MODE_EQUIRECTANGULAR
160 || projection_mode
== PROJECTION_MODE_CUBEMAP_LAYOUT_STANDARD
)
162 getProjectionMatrix(vgl
->f_sar
, vgl
->f_fovy
, prgm
->var
.ProjectionMatrix
);
163 getZoomMatrix(vgl
->f_z
, prgm
->var
.ZoomMatrix
);
165 /* vgl->vp has been reversed and is a world transform */
166 vlc_viewpoint_to_4x4(&vgl
->vp
, prgm
->var
.ViewMatrix
);
170 memcpy(prgm
->var
.ProjectionMatrix
, identity
, sizeof(identity
));
171 memcpy(prgm
->var
.ZoomMatrix
, identity
, sizeof(identity
));
172 memcpy(prgm
->var
.ViewMatrix
, identity
, sizeof(identity
));
177 static void getOrientationTransformMatrix(video_orientation_t orientation
,
178 GLfloat matrix
[static 16])
180 memcpy(matrix
, identity
, sizeof(identity
));
182 const int k_cos_pi
= -1;
183 const int k_cos_pi_2
= 0;
184 const int k_cos_n_pi_2
= 0;
186 const int k_sin_pi
= 0;
187 const int k_sin_pi_2
= 1;
188 const int k_sin_n_pi_2
= -1;
190 switch (orientation
) {
192 case ORIENT_ROTATED_90
:
193 matrix
[0 * 4 + 0] = k_cos_pi_2
;
194 matrix
[0 * 4 + 1] = -k_sin_pi_2
;
195 matrix
[1 * 4 + 0] = k_sin_pi_2
;
196 matrix
[1 * 4 + 1] = k_cos_pi_2
;
197 matrix
[3 * 4 + 1] = 1;
199 case ORIENT_ROTATED_180
:
200 matrix
[0 * 4 + 0] = k_cos_pi
;
201 matrix
[0 * 4 + 1] = -k_sin_pi
;
202 matrix
[1 * 4 + 0] = k_sin_pi
;
203 matrix
[1 * 4 + 1] = k_cos_pi
;
204 matrix
[3 * 4 + 0] = 1;
205 matrix
[3 * 4 + 1] = 1;
207 case ORIENT_ROTATED_270
:
208 matrix
[0 * 4 + 0] = k_cos_n_pi_2
;
209 matrix
[0 * 4 + 1] = -k_sin_n_pi_2
;
210 matrix
[1 * 4 + 0] = k_sin_n_pi_2
;
211 matrix
[1 * 4 + 1] = k_cos_n_pi_2
;
212 matrix
[3 * 4 + 0] = 1;
214 case ORIENT_HFLIPPED
:
215 matrix
[0 * 4 + 0] = -1;
216 matrix
[3 * 4 + 0] = 1;
218 case ORIENT_VFLIPPED
:
219 matrix
[1 * 4 + 1] = -1;
220 matrix
[3 * 4 + 1] = 1;
222 case ORIENT_TRANSPOSED
:
223 matrix
[0 * 4 + 0] = 0;
224 matrix
[1 * 4 + 1] = 0;
225 matrix
[2 * 4 + 2] = -1;
226 matrix
[0 * 4 + 1] = 1;
227 matrix
[1 * 4 + 0] = 1;
229 case ORIENT_ANTI_TRANSPOSED
:
230 matrix
[0 * 4 + 0] = 0;
231 matrix
[1 * 4 + 1] = 0;
232 matrix
[2 * 4 + 2] = -1;
233 matrix
[0 * 4 + 1] = -1;
234 matrix
[1 * 4 + 0] = -1;
235 matrix
[3 * 4 + 0] = 1;
236 matrix
[3 * 4 + 1] = 1;
243 static GLuint
BuildVertexShader(const struct vlc_gl_renderer
*renderer
,
244 unsigned plane_count
)
246 const opengl_vtable_t
*vt
= renderer
->vt
;
248 /* Basic vertex shader */
249 static const char *template =
251 "varying vec2 TexCoord0;\n"
252 "attribute vec4 MultiTexCoord0;\n"
254 "attribute vec3 VertexPosition;\n"
255 "uniform mat4 TransformMatrix;\n"
256 "uniform mat4 OrientationMatrix;\n"
257 "uniform mat4 ProjectionMatrix;\n"
258 "uniform mat4 ZoomMatrix;\n"
259 "uniform mat4 ViewMatrix;\n"
261 " TexCoord0 = vec4(TransformMatrix * OrientationMatrix * MultiTexCoord0).st;\n"
263 " gl_Position = ProjectionMatrix * ZoomMatrix * ViewMatrix\n"
264 " * vec4(VertexPosition, 1.0);\n"
267 const char *coord1_header
= plane_count
> 1 ?
268 "varying vec2 TexCoord1;\nattribute vec4 MultiTexCoord1;\n" : "";
269 const char *coord1_code
= plane_count
> 1 ?
270 " TexCoord1 = vec4(TransformMatrix * OrientationMatrix * MultiTexCoord1).st;\n" : "";
271 const char *coord2_header
= plane_count
> 2 ?
272 "varying vec2 TexCoord2;\nattribute vec4 MultiTexCoord2;\n" : "";
273 const char *coord2_code
= plane_count
> 2 ?
274 " TexCoord2 = vec4(TransformMatrix * OrientationMatrix * MultiTexCoord2).st;\n" : "";
277 if (asprintf(&code
, template, renderer
->glsl_version
, coord1_header
,
278 coord2_header
, coord1_code
, coord2_code
) < 0)
281 GLuint shader
= vt
->CreateShader(GL_VERTEX_SHADER
);
282 vt
->ShaderSource(shader
, 1, (const char **) &code
, NULL
);
283 if (renderer
->b_dump_shaders
)
284 msg_Dbg(renderer
->gl
, "\n=== Vertex shader for fourcc: %4.4s ===\n%s\n",
285 (const char *) &renderer
->interop
->fmt
.i_chroma
, code
);
286 vt
->CompileShader(shader
);
292 opengl_link_program(struct prgm
*prgm
)
294 struct vlc_gl_renderer
*renderer
= prgm
->renderer
;
295 struct vlc_gl_interop
*interop
= renderer
->interop
;
296 const opengl_vtable_t
*vt
= renderer
->vt
;
298 GLuint vertex_shader
= BuildVertexShader(renderer
, interop
->tex_count
);
302 GLuint fragment_shader
=
303 opengl_fragment_shader_init(renderer
, interop
->tex_target
,
304 interop
->sw_fmt
.i_chroma
,
305 interop
->sw_fmt
.space
);
306 if (!fragment_shader
)
309 assert(interop
->tex_target
!= 0 &&
310 interop
->tex_count
> 0 &&
311 interop
->ops
->update_textures
!= NULL
&&
312 renderer
->pf_fetch_locations
!= NULL
&&
313 renderer
->pf_prepare_shader
!= NULL
);
315 GLuint shaders
[] = { fragment_shader
, vertex_shader
};
317 /* Check shaders messages */
318 for (unsigned i
= 0; i
< 2; i
++) {
320 vt
->GetShaderiv(shaders
[i
], GL_INFO_LOG_LENGTH
, &infoLength
);
324 char *infolog
= malloc(infoLength
);
328 vt
->GetShaderInfoLog(shaders
[i
], infoLength
, &charsWritten
,
330 msg_Err(renderer
->gl
, "shader %u: %s", i
, infolog
);
335 prgm
->id
= vt
->CreateProgram();
336 vt
->AttachShader(prgm
->id
, fragment_shader
);
337 vt
->AttachShader(prgm
->id
, vertex_shader
);
338 vt
->LinkProgram(prgm
->id
);
340 vt
->DeleteShader(vertex_shader
);
341 vt
->DeleteShader(fragment_shader
);
343 /* Check program messages */
345 vt
->GetProgramiv(prgm
->id
, GL_INFO_LOG_LENGTH
, &infoLength
);
348 char *infolog
= malloc(infoLength
);
352 vt
->GetProgramInfoLog(prgm
->id
, infoLength
, &charsWritten
,
354 msg_Err(renderer
->gl
, "shader program: %s", infolog
);
358 /* If there is some message, better to check linking is ok */
359 GLint link_status
= GL_TRUE
;
360 vt
->GetProgramiv(prgm
->id
, GL_LINK_STATUS
, &link_status
);
361 if (link_status
== GL_FALSE
)
363 msg_Err(renderer
->gl
, "Unable to use program");
368 /* Fetch UniformLocations and AttribLocations */
369 #define GET_LOC(type, x, str) do { \
370 x = vt->Get##type##Location(prgm->id, str); \
373 msg_Err(renderer->gl, "Unable to Get"#type"Location(%s)", str); \
377 #define GET_ULOC(x, str) GET_LOC(Uniform, prgm->uloc.x, str)
378 #define GET_ALOC(x, str) GET_LOC(Attrib, prgm->aloc.x, str)
379 GET_ULOC(TransformMatrix
, "TransformMatrix");
380 GET_ULOC(OrientationMatrix
, "OrientationMatrix");
381 GET_ULOC(ProjectionMatrix
, "ProjectionMatrix");
382 GET_ULOC(ViewMatrix
, "ViewMatrix");
383 GET_ULOC(ZoomMatrix
, "ZoomMatrix");
385 GET_ALOC(VertexPosition
, "VertexPosition");
386 GET_ALOC(MultiTexCoord
[0], "MultiTexCoord0");
387 /* MultiTexCoord 1 and 2 can be optimized out if not used */
388 if (interop
->tex_count
> 1)
389 GET_ALOC(MultiTexCoord
[1], "MultiTexCoord1");
391 prgm
->aloc
.MultiTexCoord
[1] = -1;
392 if (interop
->tex_count
> 2)
393 GET_ALOC(MultiTexCoord
[2], "MultiTexCoord2");
395 prgm
->aloc
.MultiTexCoord
[2] = -1;
399 int ret
= prgm
->renderer
->pf_fetch_locations(prgm
->renderer
, prgm
->id
);
400 assert(ret
== VLC_SUCCESS
);
401 if (ret
!= VLC_SUCCESS
)
403 msg_Err(renderer
->gl
, "Unable to get locations from tex_conv");
410 vt
->DeleteProgram(prgm
->id
);
416 opengl_deinit_program(vout_display_opengl_t
*vgl
, struct prgm
*prgm
)
418 struct vlc_gl_renderer
*renderer
= prgm
->renderer
;
419 vlc_gl_interop_Delete(renderer
->interop
);
421 vgl
->vt
.DeleteProgram(prgm
->id
);
423 #ifdef HAVE_LIBPLACEBO
424 FREENULL(renderer
->uloc
.pl_vars
);
425 if (renderer
->pl_ctx
)
426 pl_context_destroy(&renderer
->pl_ctx
);
433 opengl_init_program(vout_display_opengl_t
*vgl
, vlc_video_context
*context
,
434 struct prgm
*prgm
, const video_format_t
*fmt
,
437 struct vlc_gl_renderer
*renderer
= calloc(1, sizeof(*renderer
));
441 struct vlc_gl_interop
*interop
=
442 vlc_gl_interop_New(vgl
->gl
, &vgl
->vt
, context
, fmt
, false);
449 renderer
->interop
= interop
;
451 renderer
->gl
= vgl
->gl
;
452 renderer
->vt
= &vgl
->vt
;
453 renderer
->b_dump_shaders
= b_dump_shaders
;
454 #if defined(USE_OPENGL_ES2)
455 renderer
->glsl_version
= 100;
456 renderer
->glsl_precision_header
= "precision highp float;\n";
458 renderer
->glsl_version
= 120;
459 renderer
->glsl_precision_header
= "";
462 #ifdef HAVE_LIBPLACEBO
463 // Create the main libplacebo context
464 renderer
->pl_ctx
= vlc_placebo_Create(VLC_OBJECT(vgl
->gl
));
465 if (renderer
->pl_ctx
) {
466 # if PL_API_VER >= 20
467 renderer
->pl_sh
= pl_shader_alloc(renderer
->pl_ctx
, NULL
);
468 # elif PL_API_VER >= 6
469 renderer
->pl_sh
= pl_shader_alloc(renderer
->pl_ctx
, NULL
, 0);
471 renderer
->pl_sh
= pl_shader_alloc(renderer
->pl_ctx
, NULL
, 0, 0);
476 prgm
->renderer
= renderer
;
478 int ret
= opengl_link_program(prgm
);
479 if (ret
!= VLC_SUCCESS
)
481 opengl_deinit_program(vgl
, prgm
);
485 getOrientationTransformMatrix(interop
->fmt
.orientation
,
486 prgm
->var
.OrientationMatrix
);
487 getViewpointMatrixes(vgl
, interop
->fmt
.projection_mode
, prgm
);
493 ResizeFormatToGLMaxTexSize(video_format_t
*fmt
, unsigned int max_tex_size
)
495 if (fmt
->i_width
> fmt
->i_height
)
497 unsigned int const vis_w
= fmt
->i_visible_width
;
498 unsigned int const vis_h
= fmt
->i_visible_height
;
499 unsigned int const nw_w
= max_tex_size
;
500 unsigned int const nw_vis_w
= nw_w
* vis_w
/ fmt
->i_width
;
502 fmt
->i_height
= nw_w
* fmt
->i_height
/ fmt
->i_width
;
504 fmt
->i_visible_height
= nw_vis_w
* vis_h
/ vis_w
;
505 fmt
->i_visible_width
= nw_vis_w
;
509 unsigned int const vis_w
= fmt
->i_visible_width
;
510 unsigned int const vis_h
= fmt
->i_visible_height
;
511 unsigned int const nw_h
= max_tex_size
;
512 unsigned int const nw_vis_h
= nw_h
* vis_h
/ fmt
->i_height
;
514 fmt
->i_width
= nw_h
* fmt
->i_width
/ fmt
->i_height
;
515 fmt
->i_height
= nw_h
;
516 fmt
->i_visible_width
= nw_vis_h
* vis_w
/ vis_h
;
517 fmt
->i_visible_height
= nw_vis_h
;
521 vout_display_opengl_t
*vout_display_opengl_New(video_format_t
*fmt
,
522 const vlc_fourcc_t
**subpicture_chromas
,
524 const vlc_viewpoint_t
*viewpoint
,
525 vlc_video_context
*context
)
527 vout_display_opengl_t
*vgl
= calloc(1, sizeof(*vgl
));
533 #if defined(USE_OPENGL_ES2) || defined(HAVE_GL_CORE_SYMBOLS)
534 #define GET_PROC_ADDR_CORE(name) vgl->vt.name = gl##name
536 #define GET_PROC_ADDR_CORE(name) GET_PROC_ADDR_EXT(name, true)
538 #define GET_PROC_ADDR_EXT(name, critical) do { \
539 vgl->vt.name = vlc_gl_GetProcAddress(gl, "gl"#name); \
540 if (vgl->vt.name == NULL && critical) { \
541 msg_Err(gl, "gl"#name" symbol not found, bailing out"); \
546 #if defined(USE_OPENGL_ES2)
547 #define GET_PROC_ADDR(name) GET_PROC_ADDR_CORE(name)
548 #define GET_PROC_ADDR_CORE_GL(name) GET_PROC_ADDR_EXT(name, false) /* optional for GLES */
550 #define GET_PROC_ADDR(name) GET_PROC_ADDR_EXT(name, true)
551 #define GET_PROC_ADDR_CORE_GL(name) GET_PROC_ADDR_CORE(name)
553 #define GET_PROC_ADDR_OPTIONAL(name) GET_PROC_ADDR_EXT(name, false) /* GL 3 or more */
555 GET_PROC_ADDR_CORE(BindTexture
);
556 GET_PROC_ADDR_CORE(BlendFunc
);
557 GET_PROC_ADDR_CORE(Clear
);
558 GET_PROC_ADDR_CORE(ClearColor
);
559 GET_PROC_ADDR_CORE(DeleteTextures
);
560 GET_PROC_ADDR_CORE(DepthMask
);
561 GET_PROC_ADDR_CORE(Disable
);
562 GET_PROC_ADDR_CORE(DrawArrays
);
563 GET_PROC_ADDR_CORE(DrawElements
);
564 GET_PROC_ADDR_CORE(Enable
);
565 GET_PROC_ADDR_CORE(Finish
);
566 GET_PROC_ADDR_CORE(Flush
);
567 GET_PROC_ADDR_CORE(GenTextures
);
568 GET_PROC_ADDR_CORE(GetError
);
569 GET_PROC_ADDR_CORE(GetIntegerv
);
570 GET_PROC_ADDR_CORE(GetString
);
571 GET_PROC_ADDR_CORE(PixelStorei
);
572 GET_PROC_ADDR_CORE(TexImage2D
);
573 GET_PROC_ADDR_CORE(TexParameterf
);
574 GET_PROC_ADDR_CORE(TexParameteri
);
575 GET_PROC_ADDR_CORE(TexSubImage2D
);
576 GET_PROC_ADDR_CORE(Viewport
);
578 GET_PROC_ADDR_CORE_GL(GetTexLevelParameteriv
);
579 GET_PROC_ADDR_CORE_GL(TexEnvf
);
581 GET_PROC_ADDR(CreateShader
);
582 GET_PROC_ADDR(ShaderSource
);
583 GET_PROC_ADDR(CompileShader
);
584 GET_PROC_ADDR(AttachShader
);
585 GET_PROC_ADDR(DeleteShader
);
587 GET_PROC_ADDR(GetProgramiv
);
588 GET_PROC_ADDR(GetShaderiv
);
589 GET_PROC_ADDR(GetProgramInfoLog
);
590 GET_PROC_ADDR(GetShaderInfoLog
);
592 GET_PROC_ADDR(GetUniformLocation
);
593 GET_PROC_ADDR(GetAttribLocation
);
594 GET_PROC_ADDR(VertexAttribPointer
);
595 GET_PROC_ADDR(EnableVertexAttribArray
);
596 GET_PROC_ADDR(UniformMatrix4fv
);
597 GET_PROC_ADDR(UniformMatrix3fv
);
598 GET_PROC_ADDR(UniformMatrix2fv
);
599 GET_PROC_ADDR(Uniform4fv
);
600 GET_PROC_ADDR(Uniform4f
);
601 GET_PROC_ADDR(Uniform3f
);
602 GET_PROC_ADDR(Uniform2f
);
603 GET_PROC_ADDR(Uniform1f
);
604 GET_PROC_ADDR(Uniform1i
);
606 GET_PROC_ADDR(CreateProgram
);
607 GET_PROC_ADDR(LinkProgram
);
608 GET_PROC_ADDR(UseProgram
);
609 GET_PROC_ADDR(DeleteProgram
);
611 GET_PROC_ADDR(ActiveTexture
);
613 GET_PROC_ADDR(GenBuffers
);
614 GET_PROC_ADDR(BindBuffer
);
615 GET_PROC_ADDR(BufferData
);
616 GET_PROC_ADDR(DeleteBuffers
);
618 GET_PROC_ADDR_OPTIONAL(GetFramebufferAttachmentParameteriv
);
620 GET_PROC_ADDR_OPTIONAL(BufferSubData
);
621 GET_PROC_ADDR_OPTIONAL(BufferStorage
);
622 GET_PROC_ADDR_OPTIONAL(MapBufferRange
);
623 GET_PROC_ADDR_OPTIONAL(FlushMappedBufferRange
);
624 GET_PROC_ADDR_OPTIONAL(UnmapBuffer
);
625 GET_PROC_ADDR_OPTIONAL(FenceSync
);
626 GET_PROC_ADDR_OPTIONAL(DeleteSync
);
627 GET_PROC_ADDR_OPTIONAL(ClientWaitSync
);
632 const char *extensions
= (const char *)vgl
->vt
.GetString(GL_EXTENSIONS
);
636 msg_Err(gl
, "glGetString returned NULL");
640 #if !defined(USE_OPENGL_ES2)
641 const unsigned char *ogl_version
= vgl
->vt
.GetString(GL_VERSION
);
642 bool supports_shaders
= strverscmp((const char *)ogl_version
, "2.0") >= 0;
643 if (!supports_shaders
)
645 msg_Err(gl
, "shaders not supported, bailing out");
651 /* Resize the format if it is greater than the maximum texture size
652 * supported by the hardware */
654 vgl
->vt
.GetIntegerv(GL_MAX_TEXTURE_SIZE
, &max_tex_size
);
656 if ((GLint
)fmt
->i_width
> max_tex_size
||
657 (GLint
)fmt
->i_height
> max_tex_size
)
658 ResizeFormatToGLMaxTexSize(fmt
, max_tex_size
);
660 /* Non-power-of-2 texture size support */
662 #if defined(USE_OPENGL_ES2)
663 /* OpenGL ES 2 includes support for non-power of 2 textures by specification
664 * so checks for extensions are bound to fail. Check for OpenGL ES version instead. */
665 supports_npot
= true;
667 supports_npot
= vlc_gl_StrHasToken(extensions
, "GL_ARB_texture_non_power_of_two") ||
668 vlc_gl_StrHasToken(extensions
, "GL_APPLE_texture_2D_limited_npot");
671 bool b_dump_shaders
= var_InheritInteger(gl
, "verbose") >= 4;
674 vlc_gl_sub_renderer_New(gl
, &vgl
->vt
, supports_npot
);
675 if (!vgl
->sub_renderer
)
677 msg_Err(gl
, "Could not create sub renderer");
683 int ret
= opengl_init_program(vgl
, context
, &vgl
->prgm
, fmt
,
685 if (ret
!= VLC_SUCCESS
)
687 msg_Warn(gl
, "could not init tex converter for %4.4s",
688 (const char *) &fmt
->i_chroma
);
689 vlc_gl_sub_renderer_Delete(vgl
->sub_renderer
);
696 const struct vlc_gl_interop
*interop
= vgl
->prgm
.renderer
->interop
;
697 /* Update the fmt to main program one */
698 vgl
->fmt
= interop
->fmt
;
699 /* The orientation is handled by the orientation matrix */
700 vgl
->fmt
.orientation
= fmt
->orientation
;
703 for (unsigned j
= 0; j
< interop
->tex_count
; j
++) {
704 const GLsizei w
= vgl
->fmt
.i_visible_width
* interop
->texs
[j
].w
.num
705 / interop
->texs
[j
].w
.den
;
706 const GLsizei h
= vgl
->fmt
.i_visible_height
* interop
->texs
[j
].h
.num
707 / interop
->texs
[j
].h
.den
;
709 vgl
->tex_width
[j
] = w
;
710 vgl
->tex_height
[j
] = h
;
712 vgl
->tex_width
[j
] = vlc_align_pot(w
);
713 vgl
->tex_height
[j
] = vlc_align_pot(h
);
717 if (!interop
->handle_texs_gen
)
719 ret
= vlc_gl_interop_GenerateTextures(interop
,
720 vgl
->tex_width
, vgl
->tex_height
,
722 if (ret
!= VLC_SUCCESS
)
724 vout_display_opengl_Delete(vgl
);
730 vgl
->vt
.Disable(GL_BLEND
);
731 vgl
->vt
.Disable(GL_DEPTH_TEST
);
732 vgl
->vt
.DepthMask(GL_FALSE
);
733 vgl
->vt
.Enable(GL_CULL_FACE
);
734 vgl
->vt
.ClearColor(0.0f
, 0.0f
, 0.0f
, 1.0f
);
735 vgl
->vt
.Clear(GL_COLOR_BUFFER_BIT
);
737 vgl
->vt
.GenBuffers(1, &vgl
->vertex_buffer_object
);
738 vgl
->vt
.GenBuffers(1, &vgl
->index_buffer_object
);
739 vgl
->vt
.GenBuffers(interop
->tex_count
, vgl
->texture_buffer_object
);
741 if (vgl
->fmt
.projection_mode
!= PROJECTION_MODE_RECTANGULAR
742 && vout_display_opengl_SetViewpoint(vgl
, viewpoint
) != VLC_SUCCESS
)
744 vout_display_opengl_Delete(vgl
);
749 if (subpicture_chromas
) {
750 *subpicture_chromas
= gl_subpicture_chromas
;
757 void vout_display_opengl_Delete(vout_display_opengl_t
*vgl
)
765 const struct vlc_gl_interop
*interop
= vgl
->prgm
.renderer
->interop
;
766 const size_t main_tex_count
= interop
->tex_count
;
767 const bool main_del_texs
= !interop
->handle_texs_gen
;
769 vlc_gl_sub_renderer_Delete(vgl
->sub_renderer
);
771 opengl_deinit_program(vgl
, &vgl
->prgm
);
773 vgl
->vt
.DeleteBuffers(1, &vgl
->vertex_buffer_object
);
774 vgl
->vt
.DeleteBuffers(1, &vgl
->index_buffer_object
);
775 vgl
->vt
.DeleteBuffers(main_tex_count
, vgl
->texture_buffer_object
);
778 vgl
->vt
.DeleteTextures(main_tex_count
, vgl
->texture
);
785 static void UpdateZ(vout_display_opengl_t
*vgl
)
787 /* Do trigonometry to calculate the minimal z value
788 * that will allow us to zoom out without seeing the outside of the
789 * sphere (black borders). */
790 float tan_fovx_2
= tanf(vgl
->f_fovx
/ 2);
791 float tan_fovy_2
= tanf(vgl
->f_fovy
/ 2);
792 float z_min
= - SPHERE_RADIUS
/ sinf(atanf(sqrtf(
793 tan_fovx_2
* tan_fovx_2
+ tan_fovy_2
* tan_fovy_2
)));
795 /* The FOV value above which z is dynamically calculated. */
796 const float z_thresh
= 90.f
;
798 if (vgl
->f_fovx
<= z_thresh
* M_PI
/ 180)
802 float f
= z_min
/ ((FIELD_OF_VIEW_DEGREES_MAX
- z_thresh
) * M_PI
/ 180);
803 vgl
->f_z
= f
* vgl
->f_fovx
- f
* z_thresh
* M_PI
/ 180;
804 if (vgl
->f_z
< z_min
)
809 static void UpdateFOVy(vout_display_opengl_t
*vgl
)
811 vgl
->f_fovy
= 2 * atanf(tanf(vgl
->f_fovx
/ 2) / vgl
->f_sar
);
814 int vout_display_opengl_SetViewpoint(vout_display_opengl_t
*vgl
,
815 const vlc_viewpoint_t
*p_vp
)
817 if (p_vp
->fov
> FIELD_OF_VIEW_DEGREES_MAX
818 || p_vp
->fov
< FIELD_OF_VIEW_DEGREES_MIN
)
821 // Convert degree into radian
822 float f_fovx
= p_vp
->fov
* (float)M_PI
/ 180.f
;
824 /* vgl->vp needs to be converted into world transform */
825 vlc_viewpoint_reverse(&vgl
->vp
, p_vp
);
827 if (fabsf(f_fovx
- vgl
->f_fovx
) >= 0.001f
)
829 /* FOVx has changed. */
830 vgl
->f_fovx
= f_fovx
;
834 getViewpointMatrixes(vgl
, vgl
->fmt
.projection_mode
, &vgl
->prgm
);
840 void vout_display_opengl_SetWindowAspectRatio(vout_display_opengl_t
*vgl
,
843 /* Each time the window size changes, we must recompute the minimum zoom
844 * since the aspect ration changes.
845 * We must also set the new current zoom value. */
849 getViewpointMatrixes(vgl
, vgl
->fmt
.projection_mode
, &vgl
->prgm
);
852 void vout_display_opengl_Viewport(vout_display_opengl_t
*vgl
, int x
, int y
,
853 unsigned width
, unsigned height
)
855 vgl
->vt
.Viewport(x
, y
, width
, height
);
858 int vout_display_opengl_Prepare(vout_display_opengl_t
*vgl
,
859 picture_t
*picture
, subpicture_t
*subpicture
)
863 struct vlc_gl_renderer
*renderer
= vgl
->prgm
.renderer
;
864 const struct vlc_gl_interop
*interop
= renderer
->interop
;
866 /* Update the texture */
867 int ret
= interop
->ops
->update_textures(interop
, vgl
->texture
, vgl
->tex_width
, vgl
->tex_height
,
869 if (ret
!= VLC_SUCCESS
)
872 ret
= vlc_gl_sub_renderer_Prepare(vgl
->sub_renderer
, subpicture
);
877 static int BuildSphere(unsigned nbPlanes
,
878 GLfloat
**vertexCoord
, GLfloat
**textureCoord
, unsigned *nbVertices
,
879 GLushort
**indices
, unsigned *nbIndices
,
880 const float *left
, const float *top
,
881 const float *right
, const float *bottom
)
883 unsigned nbLatBands
= 128;
884 unsigned nbLonBands
= 128;
886 *nbVertices
= (nbLatBands
+ 1) * (nbLonBands
+ 1);
887 *nbIndices
= nbLatBands
* nbLonBands
* 3 * 2;
889 *vertexCoord
= vlc_alloc(*nbVertices
* 3, sizeof(GLfloat
));
890 if (*vertexCoord
== NULL
)
892 *textureCoord
= vlc_alloc(nbPlanes
* *nbVertices
* 2, sizeof(GLfloat
));
893 if (*textureCoord
== NULL
)
898 *indices
= vlc_alloc(*nbIndices
, sizeof(GLushort
));
899 if (*indices
== NULL
)
906 for (unsigned lat
= 0; lat
<= nbLatBands
; lat
++) {
907 float theta
= lat
* (float) M_PI
/ nbLatBands
;
908 float sinTheta
, cosTheta
;
910 sincosf(theta
, &sinTheta
, &cosTheta
);
912 for (unsigned lon
= 0; lon
<= nbLonBands
; lon
++) {
913 float phi
= lon
* 2 * (float) M_PI
/ nbLonBands
;
914 float sinPhi
, cosPhi
;
916 sincosf(phi
, &sinPhi
, &cosPhi
);
918 float x
= cosPhi
* sinTheta
;
920 float z
= sinPhi
* sinTheta
;
922 unsigned off1
= (lat
* (nbLonBands
+ 1) + lon
) * 3;
923 (*vertexCoord
)[off1
] = SPHERE_RADIUS
* x
;
924 (*vertexCoord
)[off1
+ 1] = SPHERE_RADIUS
* y
;
925 (*vertexCoord
)[off1
+ 2] = SPHERE_RADIUS
* z
;
927 for (unsigned p
= 0; p
< nbPlanes
; ++p
)
929 unsigned off2
= (p
* (nbLatBands
+ 1) * (nbLonBands
+ 1)
930 + lat
* (nbLonBands
+ 1) + lon
) * 2;
931 float width
= right
[p
] - left
[p
];
932 float height
= bottom
[p
] - top
[p
];
933 float u
= (float)lon
/ nbLonBands
* width
;
934 float v
= (float)lat
/ nbLatBands
* height
;
935 (*textureCoord
)[off2
] = u
;
936 (*textureCoord
)[off2
+ 1] = v
;
941 for (unsigned lat
= 0; lat
< nbLatBands
; lat
++) {
942 for (unsigned lon
= 0; lon
< nbLonBands
; lon
++) {
943 unsigned first
= (lat
* (nbLonBands
+ 1)) + lon
;
944 unsigned second
= first
+ nbLonBands
+ 1;
946 unsigned off
= (lat
* nbLatBands
+ lon
) * 3 * 2;
948 (*indices
)[off
] = first
;
949 (*indices
)[off
+ 1] = second
;
950 (*indices
)[off
+ 2] = first
+ 1;
952 (*indices
)[off
+ 3] = second
;
953 (*indices
)[off
+ 4] = second
+ 1;
954 (*indices
)[off
+ 5] = first
+ 1;
962 static int BuildCube(unsigned nbPlanes
,
963 float padW
, float padH
,
964 GLfloat
**vertexCoord
, GLfloat
**textureCoord
, unsigned *nbVertices
,
965 GLushort
**indices
, unsigned *nbIndices
,
966 const float *left
, const float *top
,
967 const float *right
, const float *bottom
)
972 *vertexCoord
= vlc_alloc(*nbVertices
* 3, sizeof(GLfloat
));
973 if (*vertexCoord
== NULL
)
975 *textureCoord
= vlc_alloc(nbPlanes
* *nbVertices
* 2, sizeof(GLfloat
));
976 if (*textureCoord
== NULL
)
981 *indices
= vlc_alloc(*nbIndices
, sizeof(GLushort
));
982 if (*indices
== NULL
)
989 static const GLfloat coord
[] = {
990 -1.0, 1.0, -1.0f
, // front
995 -1.0, 1.0, 1.0f
, // back
1000 -1.0, 1.0, -1.0f
, // left
1005 1.0f
, 1.0, -1.0f
, // right
1010 -1.0, -1.0, 1.0f
, // bottom
1015 -1.0, 1.0, 1.0f
, // top
1021 memcpy(*vertexCoord
, coord
, *nbVertices
* 3 * sizeof(GLfloat
));
1023 for (unsigned p
= 0; p
< nbPlanes
; ++p
)
1025 float width
= right
[p
] - left
[p
];
1026 float height
= bottom
[p
] - top
[p
];
1028 float col
[] = {left
[p
],
1029 left
[p
] + width
* 1.f
/3,
1030 left
[p
] + width
* 2.f
/3,
1033 float row
[] = {top
[p
],
1034 top
[p
] + height
* 1.f
/2,
1037 const GLfloat tex
[] = {
1038 col
[1] + padW
, row
[1] + padH
, // front
1039 col
[1] + padW
, row
[2] - padH
,
1040 col
[2] - padW
, row
[1] + padH
,
1041 col
[2] - padW
, row
[2] - padH
,
1043 col
[3] - padW
, row
[1] + padH
, // back
1044 col
[3] - padW
, row
[2] - padH
,
1045 col
[2] + padW
, row
[1] + padH
,
1046 col
[2] + padW
, row
[2] - padH
,
1048 col
[2] - padW
, row
[0] + padH
, // left
1049 col
[2] - padW
, row
[1] - padH
,
1050 col
[1] + padW
, row
[0] + padH
,
1051 col
[1] + padW
, row
[1] - padH
,
1053 col
[0] + padW
, row
[0] + padH
, // right
1054 col
[0] + padW
, row
[1] - padH
,
1055 col
[1] - padW
, row
[0] + padH
,
1056 col
[1] - padW
, row
[1] - padH
,
1058 col
[0] + padW
, row
[2] - padH
, // bottom
1059 col
[0] + padW
, row
[1] + padH
,
1060 col
[1] - padW
, row
[2] - padH
,
1061 col
[1] - padW
, row
[1] + padH
,
1063 col
[2] + padW
, row
[0] + padH
, // top
1064 col
[2] + padW
, row
[1] - padH
,
1065 col
[3] - padW
, row
[0] + padH
,
1066 col
[3] - padW
, row
[1] - padH
,
1069 memcpy(*textureCoord
+ p
* *nbVertices
* 2, tex
,
1070 *nbVertices
* 2 * sizeof(GLfloat
));
1073 const GLushort ind
[] = {
1074 0, 1, 2, 2, 1, 3, // front
1075 6, 7, 4, 4, 7, 5, // back
1076 10, 11, 8, 8, 11, 9, // left
1077 12, 13, 14, 14, 13, 15, // right
1078 18, 19, 16, 16, 19, 17, // bottom
1079 20, 21, 22, 22, 21, 23, // top
1082 memcpy(*indices
, ind
, *nbIndices
* sizeof(GLushort
));
1087 static int BuildRectangle(unsigned nbPlanes
,
1088 GLfloat
**vertexCoord
, GLfloat
**textureCoord
, unsigned *nbVertices
,
1089 GLushort
**indices
, unsigned *nbIndices
,
1090 const float *left
, const float *top
,
1091 const float *right
, const float *bottom
)
1096 *vertexCoord
= vlc_alloc(*nbVertices
* 3, sizeof(GLfloat
));
1097 if (*vertexCoord
== NULL
)
1099 *textureCoord
= vlc_alloc(nbPlanes
* *nbVertices
* 2, sizeof(GLfloat
));
1100 if (*textureCoord
== NULL
)
1105 *indices
= vlc_alloc(*nbIndices
, sizeof(GLushort
));
1106 if (*indices
== NULL
)
1108 free(*textureCoord
);
1113 static const GLfloat coord
[] = {
1120 memcpy(*vertexCoord
, coord
, *nbVertices
* 3 * sizeof(GLfloat
));
1122 for (unsigned p
= 0; p
< nbPlanes
; ++p
)
1124 const GLfloat tex
[] = {
1131 memcpy(*textureCoord
+ p
* *nbVertices
* 2, tex
,
1132 *nbVertices
* 2 * sizeof(GLfloat
));
1135 const GLushort ind
[] = {
1140 memcpy(*indices
, ind
, *nbIndices
* sizeof(GLushort
));
1145 static int SetupCoords(vout_display_opengl_t
*vgl
,
1146 const float *left
, const float *top
,
1147 const float *right
, const float *bottom
)
1149 const struct vlc_gl_interop
*interop
= vgl
->prgm
.renderer
->interop
;
1151 GLfloat
*vertexCoord
, *textureCoord
;
1153 unsigned nbVertices
, nbIndices
;
1156 switch (vgl
->fmt
.projection_mode
)
1158 case PROJECTION_MODE_RECTANGULAR
:
1159 i_ret
= BuildRectangle(interop
->tex_count
,
1160 &vertexCoord
, &textureCoord
, &nbVertices
,
1161 &indices
, &nbIndices
,
1162 left
, top
, right
, bottom
);
1164 case PROJECTION_MODE_EQUIRECTANGULAR
:
1165 i_ret
= BuildSphere(interop
->tex_count
,
1166 &vertexCoord
, &textureCoord
, &nbVertices
,
1167 &indices
, &nbIndices
,
1168 left
, top
, right
, bottom
);
1170 case PROJECTION_MODE_CUBEMAP_LAYOUT_STANDARD
:
1171 i_ret
= BuildCube(interop
->tex_count
,
1172 (float)vgl
->fmt
.i_cubemap_padding
/ vgl
->fmt
.i_width
,
1173 (float)vgl
->fmt
.i_cubemap_padding
/ vgl
->fmt
.i_height
,
1174 &vertexCoord
, &textureCoord
, &nbVertices
,
1175 &indices
, &nbIndices
,
1176 left
, top
, right
, bottom
);
1179 i_ret
= VLC_EGENERIC
;
1183 if (i_ret
!= VLC_SUCCESS
)
1186 for (unsigned j
= 0; j
< interop
->tex_count
; j
++)
1188 vgl
->vt
.BindBuffer(GL_ARRAY_BUFFER
, vgl
->texture_buffer_object
[j
]);
1189 vgl
->vt
.BufferData(GL_ARRAY_BUFFER
, nbVertices
* 2 * sizeof(GLfloat
),
1190 textureCoord
+ j
* nbVertices
* 2, GL_STATIC_DRAW
);
1193 vgl
->vt
.BindBuffer(GL_ARRAY_BUFFER
, vgl
->vertex_buffer_object
);
1194 vgl
->vt
.BufferData(GL_ARRAY_BUFFER
, nbVertices
* 3 * sizeof(GLfloat
),
1195 vertexCoord
, GL_STATIC_DRAW
);
1197 vgl
->vt
.BindBuffer(GL_ELEMENT_ARRAY_BUFFER
, vgl
->index_buffer_object
);
1198 vgl
->vt
.BufferData(GL_ELEMENT_ARRAY_BUFFER
, nbIndices
* sizeof(GLushort
),
1199 indices
, GL_STATIC_DRAW
);
1205 vgl
->nb_indices
= nbIndices
;
1210 static void DrawWithShaders(vout_display_opengl_t
*vgl
, struct prgm
*prgm
)
1212 struct vlc_gl_renderer
*renderer
= prgm
->renderer
;
1213 const struct vlc_gl_interop
*interop
= renderer
->interop
;
1214 renderer
->pf_prepare_shader(renderer
, vgl
->tex_width
, vgl
->tex_height
, 1.0f
);
1216 for (unsigned j
= 0; j
< interop
->tex_count
; j
++) {
1217 assert(vgl
->texture
[j
] != 0);
1218 vgl
->vt
.ActiveTexture(GL_TEXTURE0
+j
);
1219 vgl
->vt
.BindTexture(interop
->tex_target
, vgl
->texture
[j
]);
1221 vgl
->vt
.BindBuffer(GL_ARRAY_BUFFER
, vgl
->texture_buffer_object
[j
]);
1223 assert(prgm
->aloc
.MultiTexCoord
[j
] != -1);
1224 vgl
->vt
.EnableVertexAttribArray(prgm
->aloc
.MultiTexCoord
[j
]);
1225 vgl
->vt
.VertexAttribPointer(prgm
->aloc
.MultiTexCoord
[j
], 2, GL_FLOAT
,
1229 vgl
->vt
.BindBuffer(GL_ARRAY_BUFFER
, vgl
->vertex_buffer_object
);
1230 vgl
->vt
.BindBuffer(GL_ELEMENT_ARRAY_BUFFER
, vgl
->index_buffer_object
);
1231 vgl
->vt
.EnableVertexAttribArray(prgm
->aloc
.VertexPosition
);
1232 vgl
->vt
.VertexAttribPointer(prgm
->aloc
.VertexPosition
, 3, GL_FLOAT
, 0, 0, 0);
1234 const GLfloat
*tm
= NULL
;
1235 if (interop
->ops
&& interop
->ops
->get_transform_matrix
)
1236 tm
= interop
->ops
->get_transform_matrix(interop
);
1240 vgl
->vt
.UniformMatrix4fv(prgm
->uloc
.TransformMatrix
, 1, GL_FALSE
, tm
);
1242 vgl
->vt
.UniformMatrix4fv(prgm
->uloc
.OrientationMatrix
, 1, GL_FALSE
,
1243 prgm
->var
.OrientationMatrix
);
1244 vgl
->vt
.UniformMatrix4fv(prgm
->uloc
.ProjectionMatrix
, 1, GL_FALSE
,
1245 prgm
->var
.ProjectionMatrix
);
1246 vgl
->vt
.UniformMatrix4fv(prgm
->uloc
.ViewMatrix
, 1, GL_FALSE
,
1247 prgm
->var
.ViewMatrix
);
1248 vgl
->vt
.UniformMatrix4fv(prgm
->uloc
.ZoomMatrix
, 1, GL_FALSE
,
1249 prgm
->var
.ZoomMatrix
);
1251 vgl
->vt
.DrawElements(GL_TRIANGLES
, vgl
->nb_indices
, GL_UNSIGNED_SHORT
, 0);
1255 static void GetTextureCropParamsForStereo(unsigned i_nbTextures
,
1256 const float *stereoCoefs
,
1257 const float *stereoOffsets
,
1258 float *left
, float *top
,
1259 float *right
, float *bottom
)
1261 for (unsigned i
= 0; i
< i_nbTextures
; ++i
)
1263 float f_2eyesWidth
= right
[i
] - left
[i
];
1264 left
[i
] = left
[i
] + f_2eyesWidth
* stereoOffsets
[0];
1265 right
[i
] = left
[i
] + f_2eyesWidth
* stereoCoefs
[0];
1267 float f_2eyesHeight
= bottom
[i
] - top
[i
];
1268 top
[i
] = top
[i
] + f_2eyesHeight
* stereoOffsets
[1];
1269 bottom
[i
] = top
[i
] + f_2eyesHeight
* stereoCoefs
[1];
1273 static void TextureCropForStereo(vout_display_opengl_t
*vgl
,
1274 float *left
, float *top
,
1275 float *right
, float *bottom
)
1277 const struct vlc_gl_interop
*interop
= vgl
->prgm
.renderer
->interop
;
1279 float stereoCoefs
[2];
1280 float stereoOffsets
[2];
1282 switch (vgl
->fmt
.multiview_mode
)
1284 case MULTIVIEW_STEREO_TB
:
1285 // Display only the left eye.
1286 stereoCoefs
[0] = 1; stereoCoefs
[1] = 0.5;
1287 stereoOffsets
[0] = 0; stereoOffsets
[1] = 0;
1288 GetTextureCropParamsForStereo(interop
->tex_count
,
1289 stereoCoefs
, stereoOffsets
,
1290 left
, top
, right
, bottom
);
1292 case MULTIVIEW_STEREO_SBS
:
1293 // Display only the left eye.
1294 stereoCoefs
[0] = 0.5; stereoCoefs
[1] = 1;
1295 stereoOffsets
[0] = 0; stereoOffsets
[1] = 0;
1296 GetTextureCropParamsForStereo(interop
->tex_count
,
1297 stereoCoefs
, stereoOffsets
,
1298 left
, top
, right
, bottom
);
1305 int vout_display_opengl_Display(vout_display_opengl_t
*vgl
,
1306 const video_format_t
*source
)
1308 GL_ASSERT_NOERROR();
1310 /* Why drawing here and not in Render()? Because this way, the
1311 OpenGL providers can call vout_display_opengl_Display to force redraw.
1312 Currently, the OS X provider uses it to get a smooth window resizing */
1313 vgl
->vt
.Clear(GL_COLOR_BUFFER_BIT
);
1315 vgl
->vt
.UseProgram(vgl
->prgm
.id
);
1317 if (source
->i_x_offset
!= vgl
->last_source
.i_x_offset
1318 || source
->i_y_offset
!= vgl
->last_source
.i_y_offset
1319 || source
->i_visible_width
!= vgl
->last_source
.i_visible_width
1320 || source
->i_visible_height
!= vgl
->last_source
.i_visible_height
)
1322 float left
[PICTURE_PLANE_MAX
];
1323 float top
[PICTURE_PLANE_MAX
];
1324 float right
[PICTURE_PLANE_MAX
];
1325 float bottom
[PICTURE_PLANE_MAX
];
1326 const struct vlc_gl_renderer
*renderer
= vgl
->prgm
.renderer
;
1327 const struct vlc_gl_interop
*interop
= renderer
->interop
;
1328 for (unsigned j
= 0; j
< interop
->tex_count
; j
++)
1330 float scale_w
= (float)interop
->texs
[j
].w
.num
/ interop
->texs
[j
].w
.den
1331 / vgl
->tex_width
[j
];
1332 float scale_h
= (float)interop
->texs
[j
].h
.num
/ interop
->texs
[j
].h
.den
1333 / vgl
->tex_height
[j
];
1335 /* Warning: if NPOT is not supported a larger texture is
1336 allocated. This will cause right and bottom coordinates to
1337 land on the edge of two texels with the texels to the
1338 right/bottom uninitialized by the call to
1339 glTexSubImage2D. This might cause a green line to appear on
1340 the right/bottom of the display.
1341 There are two possible solutions:
1342 - Manually mirror the edges of the texture.
1343 - Add a "-1" when computing right and bottom, however the
1344 last row/column might not be displayed at all.
1346 left
[j
] = (source
->i_x_offset
+ 0 ) * scale_w
;
1347 top
[j
] = (source
->i_y_offset
+ 0 ) * scale_h
;
1348 right
[j
] = (source
->i_x_offset
+ source
->i_visible_width
) * scale_w
;
1349 bottom
[j
] = (source
->i_y_offset
+ source
->i_visible_height
) * scale_h
;
1352 TextureCropForStereo(vgl
, left
, top
, right
, bottom
);
1353 int ret
= SetupCoords(vgl
, left
, top
, right
, bottom
);
1354 if (ret
!= VLC_SUCCESS
)
1357 vgl
->last_source
.i_x_offset
= source
->i_x_offset
;
1358 vgl
->last_source
.i_y_offset
= source
->i_y_offset
;
1359 vgl
->last_source
.i_visible_width
= source
->i_visible_width
;
1360 vgl
->last_source
.i_visible_height
= source
->i_visible_height
;
1362 DrawWithShaders(vgl
, &vgl
->prgm
);
1364 int ret
= vlc_gl_sub_renderer_Draw(vgl
->sub_renderer
);
1365 if (ret
!= VLC_SUCCESS
)
1369 vlc_gl_Swap(vgl
->gl
);
1371 GL_ASSERT_NOERROR();