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>
37 #include <vlc_subpicture.h>
38 #include <vlc_opengl.h>
39 #include <vlc_modules.h>
41 #include <vlc_viewpoint.h>
46 #include "vout_helper.h"
50 #include "sampler_priv.h"
51 #include "sub_renderer.h"
53 struct vout_display_opengl_t
{
56 struct vlc_gl_api api
;
58 struct vlc_gl_interop
*interop
;
59 struct vlc_gl_renderer
*renderer
; /**< weak reference */
61 struct vlc_gl_filters
*filters
;
63 struct vlc_gl_interop
*sub_interop
;
64 struct vlc_gl_sub_renderer
*sub_renderer
;
67 static const vlc_fourcc_t gl_subpicture_chromas
[] = {
73 ResizeFormatToGLMaxTexSize(video_format_t
*fmt
, unsigned int max_tex_size
)
75 if (fmt
->i_width
> fmt
->i_height
)
77 unsigned int const vis_w
= fmt
->i_visible_width
;
78 unsigned int const vis_h
= fmt
->i_visible_height
;
79 unsigned int const nw_w
= max_tex_size
;
80 unsigned int const nw_vis_w
= nw_w
* vis_w
/ fmt
->i_width
;
82 fmt
->i_height
= nw_w
* fmt
->i_height
/ fmt
->i_width
;
84 fmt
->i_visible_height
= nw_vis_w
* vis_h
/ vis_w
;
85 fmt
->i_visible_width
= nw_vis_w
;
89 unsigned int const vis_w
= fmt
->i_visible_width
;
90 unsigned int const vis_h
= fmt
->i_visible_height
;
91 unsigned int const nw_h
= max_tex_size
;
92 unsigned int const nw_vis_h
= nw_h
* vis_h
/ fmt
->i_height
;
94 fmt
->i_width
= nw_h
* fmt
->i_width
/ fmt
->i_height
;
96 fmt
->i_visible_width
= nw_vis_h
* vis_w
/ vis_h
;
97 fmt
->i_visible_height
= nw_vis_h
;
101 vout_display_opengl_t
*vout_display_opengl_New(video_format_t
*fmt
,
102 const vlc_fourcc_t
**subpicture_chromas
,
104 const vlc_viewpoint_t
*viewpoint
,
105 vlc_video_context
*context
)
107 vout_display_opengl_t
*vgl
= calloc(1, sizeof(*vgl
));
113 int ret
= vlc_gl_api_Init(&vgl
->api
, gl
);
114 if (ret
!= VLC_SUCCESS
)
117 const struct vlc_gl_api
*api
= &vgl
->api
;
118 const opengl_vtable_t
*vt
= &api
->vt
;
120 #if !defined(USE_OPENGL_ES2)
121 const unsigned char *ogl_version
= vt
->GetString(GL_VERSION
);
122 bool supports_shaders
= strverscmp((const char *)ogl_version
, "2.0") >= 0;
123 if (!supports_shaders
)
125 msg_Err(gl
, "shaders not supported, bailing out");
130 /* Resize the format if it is greater than the maximum texture size
131 * supported by the hardware */
133 vt
->GetIntegerv(GL_MAX_TEXTURE_SIZE
, &max_tex_size
);
135 if ((GLint
)fmt
->i_width
> max_tex_size
||
136 (GLint
)fmt
->i_height
> max_tex_size
)
137 ResizeFormatToGLMaxTexSize(fmt
, max_tex_size
);
139 vgl
->interop
= vlc_gl_interop_New(gl
, api
, context
, fmt
);
142 msg_Err(gl
, "Could not create interop");
146 vgl
->filters
= vlc_gl_filters_New(gl
, api
, vgl
->interop
);
149 msg_Err(gl
, "Could not create filters");
153 /* The renderer is the only filter, for now */
154 struct vlc_gl_filter
*renderer_filter
=
155 vlc_gl_filters_Append(vgl
->filters
, "renderer", NULL
);
156 if (!renderer_filter
)
158 msg_Warn(gl
, "Could not create renderer for %4.4s",
159 (const char *) &fmt
->i_chroma
);
163 /* The renderer is a special filter: we need its concrete instance to
164 * forward SetViewpoint() */
165 vgl
->renderer
= renderer_filter
->sys
;
167 ret
= vlc_gl_filters_InitFramebuffers(vgl
->filters
);
168 if (ret
!= VLC_SUCCESS
)
170 msg_Err(gl
, "Could not init filters framebuffers");
174 vgl
->sub_interop
= vlc_gl_interop_NewForSubpictures(gl
, api
);
175 if (!vgl
->sub_interop
)
177 msg_Err(gl
, "Could not create sub interop");
182 vlc_gl_sub_renderer_New(gl
, api
, vgl
->sub_interop
);
183 if (!vgl
->sub_renderer
)
185 msg_Err(gl
, "Could not create sub renderer");
186 goto delete_sub_interop
;
189 GL_ASSERT_NOERROR(vt
);
191 if (fmt
->projection_mode
!= PROJECTION_MODE_RECTANGULAR
192 && vout_display_opengl_SetViewpoint(vgl
, viewpoint
) != VLC_SUCCESS
)
193 goto delete_sub_renderer
;
195 /* Forward to the core the changes to the input format requested by the
197 *fmt
= vgl
->interop
->fmt_in
;
199 if (subpicture_chromas
) {
200 *subpicture_chromas
= gl_subpicture_chromas
;
203 GL_ASSERT_NOERROR(vt
);
207 vlc_gl_sub_renderer_Delete(vgl
->sub_renderer
);
209 vlc_gl_interop_Delete(vgl
->sub_interop
);
211 vlc_gl_filters_Delete(vgl
->filters
);
213 vlc_gl_interop_Delete(vgl
->interop
);
220 void vout_display_opengl_Delete(vout_display_opengl_t
*vgl
)
222 const opengl_vtable_t
*vt
= &vgl
->api
.vt
;
224 GL_ASSERT_NOERROR(vt
);
230 vlc_gl_sub_renderer_Delete(vgl
->sub_renderer
);
231 vlc_gl_interop_Delete(vgl
->sub_interop
);
233 vlc_gl_filters_Delete(vgl
->filters
);
234 vlc_gl_interop_Delete(vgl
->interop
);
236 GL_ASSERT_NOERROR(vt
);
241 int vout_display_opengl_SetViewpoint(vout_display_opengl_t
*vgl
,
242 const vlc_viewpoint_t
*p_vp
)
244 return vlc_gl_renderer_SetViewpoint(vgl
->renderer
, p_vp
);
247 void vout_display_opengl_SetWindowAspectRatio(vout_display_opengl_t
*vgl
,
250 vlc_gl_renderer_SetWindowAspectRatio(vgl
->renderer
, f_sar
);
253 void vout_display_opengl_Viewport(vout_display_opengl_t
*vgl
, int x
, int y
,
254 unsigned width
, unsigned height
)
256 vlc_gl_filters_SetViewport(vgl
->filters
, x
, y
, width
, height
);
259 int vout_display_opengl_Prepare(vout_display_opengl_t
*vgl
,
260 picture_t
*picture
, subpicture_t
*subpicture
)
262 GL_ASSERT_NOERROR(&vgl
->api
.vt
);
264 int ret
= vlc_gl_filters_UpdatePicture(vgl
->filters
, picture
);
265 if (ret
!= VLC_SUCCESS
)
268 ret
= vlc_gl_sub_renderer_Prepare(vgl
->sub_renderer
, subpicture
);
269 GL_ASSERT_NOERROR(&vgl
->api
.vt
);
272 int vout_display_opengl_Display(vout_display_opengl_t
*vgl
)
274 GL_ASSERT_NOERROR(&vgl
->api
.vt
);
276 /* Why drawing here and not in Render()? Because this way, the
277 OpenGL providers can call vout_display_opengl_Display to force redraw.
278 Currently, the OS X provider uses it to get a smooth window resizing */
280 int ret
= vlc_gl_filters_Draw(vgl
->filters
);
281 if (ret
!= VLC_SUCCESS
)
284 ret
= vlc_gl_sub_renderer_Draw(vgl
->sub_renderer
);
285 if (ret
!= VLC_SUCCESS
)
289 vlc_gl_Swap(vgl
->gl
);
291 GL_ASSERT_NOERROR(&vgl
->api
.vt
);