Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • videolan/vlc
  • chouquette/vlc
  • bakiewicz.marek122/vlc
  • devnexen/vlc
  • rohanrajpal/vlc
  • blurrrb/vlc
  • gsoc/gsoc2019/darkapex/vlc
  • b1ue/vlc
  • fkuehne/vlc
  • magsoft/vlc
  • chub/vlc
  • cramiro9/vlc
  • robUx4/vlc
  • rom1v/vlc
  • akshayaky/vlc
  • tmk907/vlc
  • akymaster/vlc
  • govind.sharma/vlc
  • psilokos/vlc
  • xjbeta/vlc
  • jahan/vlc
  • 1480c1/vlc
  • amanchande/vlc
  • aaqib/vlc
  • rist/vlc
  • apol/vlc
  • mindfreeze/vlc
  • alexandre-janniaux/vlc
  • sandsmark/vlc
  • jagannatharjun/vlc
  • gsoc/gsoc2020/matiaslgonzalez/vlc
  • gsoc/gsoc2020/jagannatharjun/vlc
  • mstorsjo/vlc
  • gsoc/gsoc2020/vedenta/vlc
  • gsoc/gsoc2020/arnav-ishaan/vlc
  • gsoc/gsoc2020/andreduong/vlc
  • fuzun/vlc
  • gsoc/gsoc2020/vatsin/vlc
  • gsoc/gsoc2020/sagid/vlc
  • yaron/vlc
  • Phoenix/vlc
  • Garf/vlc
  • ePiratWorkarounds/vlc
  • tguillem/vlc
  • jnqnfe/vlc
  • mdc/vlc
  • Vedaa/vlc
  • rasa/vlc
  • quink/vlc
  • yealo/vlc
  • aleksey_ak/vlc
  • ePirat/vlc
  • ilya.yanok/vlc
  • asenat/vlc
  • m/vlc
  • bunjee/vlc
  • BLumia/vlc
  • sagudev/vlc
  • hamedmonji30/vlc
  • nullgemm/vlc
  • DivyamAhuja/vlc
  • thesamesam/vlc
  • dag7/vlc
  • snehil101/vlc
  • haasn/vlc
  • jbk/vlc
  • ValZapod/vlc
  • mfkl/vlc
  • WangChuan/vlc
  • core1024/vlc
  • GhostVaibhav/vlc
  • dfuhrmann/vlc
  • davide.prade/vlc
  • tmatth/vlc
  • Courmisch/vlc
  • zouya/vlc
  • hpi/vlc
  • EwoutH/vlc
  • aleung27/vlc
  • hengwu0/vlc
  • saladin/vlc
  • ashuio/vlc
  • richselwood/vlc
  • verma16Ayush/vlc
  • chemicalflash/vlc
  • PoignardAzur/vlc
  • huangjieNT/vlc
  • Blake-Haydon/vlc
  • AnuthaDev/vlc
  • gsoc/gsoc2021/mpd/vlc
  • nicolas_lequec/vlc
  • sambassaly/vlc
  • thresh/vlc
  • bonniegong/vlc
  • myaashish/vlc
  • stavros.vagionitis/vlc
  • ileoo/vlc
  • louis-santucci/vlc
  • cchristiansen/vlc
  • sabyasachi07/vlc
  • AbduAmeen/vlc
  • ashishb0410/vlc
  • urbanhusky/vlc
  • davidepietrasanta/vlc
  • riksleutelstad/vlc
  • jeremyVignelles/vlc
  • komh/vlc
  • iamjithinjohn/vlc
  • JohannesKauffmann/vlc2
  • kunglao/vlc
  • natzberg/vlc
  • jill/vlc
  • cwendling/vlc
  • adufou/vlc
  • ErwanAirone/vlc
  • HasinduDilshan10/vlc
  • vagrantc/vlc
  • rafiv/macos-bigsur-icon
  • Aymeriic/vlc
  • saranshg20/vlc
  • metzlove24/vlc
  • linkfanel/vlc
  • Ds886/vlc
  • metehan-arslan/vlc
  • Skantes/vlc
  • kgsandundananjaya96/vlc
  • mitchcapper/vlc
  • advaitgupta/vlc
  • StefanBruens/vlc
  • ratajs/vlc
  • T.M.F.B.3761/vlc
  • m222059/vlc
  • casemerrick/vlc
  • joshuaword2alt/vlc
  • sjwaddy/vlc
  • dima/vlc
  • Ybalrid/vlc
  • umxprime/vlc
  • eschmidt/vlc
  • vannieuwenhuysenmichelle/vlc
  • badcf00d/vlc
  • wesinator/vlc
  • louis/vlc
  • xqq/vlc
  • EmperorYP7/vlc
  • NicoLiam/vlc
  • loveleen/vlc
  • rofferom/vlc
  • rbultje/vlc
  • TheUnamed/vlc
  • pratiksharma341/vlc
  • Saurab17/vlc
  • purist.coder/vlc
  • Shuicheng/vlc
  • mdrrubel292/vlc
  • silverbleu00/vlc
  • metif12/vlc
  • asher-m/vlc
  • jeffk/vlc
  • Brandonbr1/vlc
  • beautyyuyanli/vlc
  • rego21/vlc
  • muyangren907/vlc
  • collectionbylawrencejason/vlc
  • evelez/vlc
  • GSMgeeth/vlc
  • Oneric/vlc
  • TJ5/vlc
  • XuanTung95/vlc
  • darrenjenny21/vlc
  • Trenly/vlc
  • RockyTDR/vlc
  • mjakubowski/vlc
  • caprica/vlc
  • ForteFrankie/vlc
  • seannamiller19/vlc
  • junlon2006/vlc
  • kiwiren6666/vlc
  • iuseiphonexs/vlc
  • fenngtun/vlc
  • Rajdutt999/vlc
  • typx/vlc
  • leon.vitanos/vlc
  • robertogarci0938/vlc
  • gsoc/gsoc2022/luc65r/vlc-mpd
  • skeller/vlc
  • MCJack123/vlc
  • luc65r/vlc-mpd
  • popov895/vlc
  • claucambra/vlc
  • brad/vlc
  • matthewmurua88/vlc
  • Tomas8874/vlc
  • philenotfound/vlc
  • makita-do3/vlc
  • LZXCorp/vlc
  • mar0x/vlc
  • senojetkennedy0102/vlc
  • shaneb243/vlc
  • ahmadbader/vlc
  • rajduttcse26/vlc-audio-filters
  • Juniorzito8415/vlc
  • achernyakov/vlc
  • lucasjetgroup/vlc
  • pupdoggy666/vlc
  • gmde9363/vlc
  • alexnwayne/vlc
  • bahareebrahimi781/vlc
  • hamad633666/vlc
  • umghof3112/vlc
  • joe0199771874/vlc
  • Octocats66666666/vlc
  • jjm_223/vlc
  • btech10110.19/vlc
  • sunnykfc028/vlc-audio-filters
  • loic/vlc
  • nguyenminhducmx1/vlc
  • JanekKrueger/vlc
  • bstubbington2/vlc
  • rcombs/vlc
  • Ordissimo/vlc
  • king7532/vlc
  • noobsauce101/vlc
  • schong0525/vlc
  • myQwil/vlc
  • apisbg91/vlc
  • geeboy0101017/vlc
  • kim.faughey/vlc
  • nurupo/vlc
  • yyusea/vlc
  • 0711235879.khco/vlc
  • ialo/vlc
  • iloveyeye2/vlc
  • gdtdftdqtd/vlc
  • leandroconsiglio/vlc
  • AndyHTML2012/vlc
  • ncz/vlc
  • lucenticus/vlc
  • knr1931/vlc
  • kjoonlee/vlc
  • chandrakant100/vlc-qt
  • johge42/vlc
  • polter/vlc
  • hexchain/vlc
  • Tushwrld/vlc
  • mztea928/vlc
  • jbelloncastro/vlc
  • alvinhochun/vlc
  • ghostpiratecrow/vlc
  • ujjwaltwitx/vlc
  • alexsonarin06/vlc
  • adrianbon76/vlc
  • altsod/vlc
  • damien.lucas44/vlc
  • dmytrivtaisa/vlc
  • utk202/vlc
  • aaxhrj/vlc
  • thomas.hermes/vlc
  • structurenewworldorder/vlc
  • slomo/vlc
  • wantlamy/vlc
  • musc.o3cminc/vlc
  • thebarshablog/vlc
  • kerrick/vlc
  • kratos142518/vlc
  • leogps/vlc
  • vacantron/vlc
  • luna_koly/vlc
  • Ratio2/vlc
  • anuoshemohammad/vlc
  • apsun/vlc
  • aaa1115910/vlc
  • alimotmoyo/vlc
  • Ambossmann/vlc
  • Sam-LearnsToCode/vlc
  • Chilledheart/vlc
  • Labnann/vlc
  • ktcoooot1/vlc
  • mohit-marathe/vlc
  • johnddx/vlc
  • manstabuk/vlc
  • Omar-ahmed314/vlc
  • vineethkm/vlc
  • 9Enemi86/vlc
  • radoslav.m.panteleev/vlc
  • ashishami2002/vlc
  • Corbax/vlc
  • firnasahmed/vlc
  • pelayarmalam4/vlc
  • c0ff330k/vlc
  • shikhindahikar/vlc
  • l342723951/vlc
  • christianschwandner/vlc
  • douniwan5788/vlc
  • 7damian7/vlc
  • ferdnyc/vlc
  • f.ales1/vlc
  • pandagby/vlc
  • BaaBaa/vlc
  • jewe37/vlc
  • w00drow/vlc
  • russelltg/vlc
  • ironicallygod/vlc
  • soumyaDghosh/vlc
  • linzihao1999/vlc
  • deyayush6/vlc
  • mibi88/vlc
  • newabdallah10/vlc
  • jhorbincolombia/vlc
  • rimvihaqueshupto/vlc
  • andrewkhon98/vlc
  • fab78/vlc
  • lapaz17/vlc
  • amanna13/vlc
  • mdakram28/vlc
  • 07jw1980/vlc
  • sohamgupta/vlc
  • Eson-Jia1/vlc
  • Sumou/vlc
  • vikram-kangotra/vlc
  • chalice191/vlc
  • olivercalder/vlc
  • aaasg4001/vlc
  • zipdox/vlc
  • kwizart/vlc
  • Dragon-S/vlc
  • jdemeule/vlc
  • gabriel_lt/vlc
  • locutusofborg/vlc
  • sammirata/vlc-librist
  • another/vlc
  • Benjamin_Loison/vlc
  • ahmedmoselhi/vlc
  • petergaal/vlc
  • huynhsontung/vlc
  • dariusmihut/vlc
  • tvermaashutosh/vlc
  • buti/vlc
  • Niram7777/vlc
  • rohan-here/vlc
  • balaji-sivasakthi/vlc
  • rlindner81/vlc
  • Kakadus/vlc
  • djain/vlc
  • ABBurmeister/vlc
  • craighuggins/vlc
  • orbea/vlc
  • maxos/vlc
  • aakarshmj/vlc
  • kblaschke/vlc
  • ankitm/vlc
  • advait-0/vlc
  • mohak2003/vlc
  • yselkowitz/vlc
  • AZM999/vlc-azm
  • andrey.turkin/vlc
  • Disha-Baghel/vlc
  • nowrep/vlc
  • Apeng/vlc
  • Choucroute_melba/vlc
  • autra/vlc
  • eclipseo/vlc
  • fhuber/vlc
  • olafhering/vlc
  • sdasda7777/vlc
  • 1div0/vlc
  • skosnits/vlc-extended-playlist-support
  • dnicolson/vlc
  • Timshel/vlc
  • octopols/vlc
  • MangalK/vlc
  • nima64/vlc
  • misawai/vlc
  • Alexander-Wilms/vlc
  • Maxime2/vlc-fork-for-visualizer
  • ww/vlc
  • jeske/vlc
  • sgross-emlix/vlc
  • morenonatural/vlc
  • freakingLovesVLC/vlc
  • borisgolovnev/vlc
  • mpromonet/vlc
  • diogo.simao-marques/vlc
  • masstock/vlc
  • pratikpatel8982/vlc
  • hugok79/vlc
  • longervision/vlc
  • abhiudaysurya/vlc
  • rishabhgarg/vlc
  • tumic/vlc
  • cart/vlc
  • shubham442/vlc
  • Aditya692005/vlc
  • sammirata/vlc4
  • syrykh/vlc
  • Vvorcun/macos-new-icon
  • AyaanshC/vlc
  • nasso/vlc
  • Quark/vlc
  • sebastinas/vlc
  • rhstone/vlc
  • talregev/vlc
  • Managor/vlc
  • abdsaber000/vlc
404 results
Show changes
Commits on Source (18)
Showing
with 522 additions and 284 deletions
......@@ -100,6 +100,8 @@ VLC_API vlc_gl_t *vlc_gl_CreateOffscreen(vlc_object_t *parent,
VLC_API void vlc_gl_Release(vlc_gl_t *);
VLC_API void vlc_gl_Hold(vlc_gl_t *);
VLC_API bool vlc_gl_HasExtension(vlc_gl_t *gl, const char *extension);
static inline int vlc_gl_MakeCurrent(vlc_gl_t *gl)
{
return gl->make_current(gl);
......
/*****************************************************************************
* vlc_opengl_interop.h: VLC picture_t to GL texture API
*****************************************************************************
* Copyright (C) 2019-2022 Videolabs
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifndef VLC_GL_INTEROP_H
#define VLC_GL_INTEROP_H 1
#include <vlc_es.h>
#include <vlc_picture.h>
struct vlc_gl_interop;
struct vlc_video_context;
struct vlc_gl_interop_ops {
/**
* Callback to allocate data for bound textures
*
* This function pointer can be NULL. Software converters should call
* glTexImage2D() to allocate textures data (it will be deallocated by the
* caller when calling glDeleteTextures()). Won't be called if
* handle_texs_gen is true.
*
* \param interop the OpenGL interop
* \param textures array of textures to bind (one per plane)
* \param tex_width array of tex width (one per plane)
* \param tex_height array of tex height (one per plane)
* \return VLC_SUCCESS or a VLC error
*/
int (*allocate_textures)(const struct vlc_gl_interop *interop,
uint32_t textures[], const int32_t tex_width[],
const int32_t tex_height[]);
/**
* Callback to update a picture
*
* This function pointer cannot be NULL. The implementation should upload
* every planes of the picture.
*
* \param interop the OpenGL interop
* \param textures array of textures to bind (one per plane)
* \param tex_width array of tex width (one per plane)
* \param tex_height array of tex height (one per plane)
* \param pic picture to update
* \param plane_offset offsets of each picture planes to read data from
* (one per plane, can be NULL)
* \return VLC_SUCCESS or a VLC error
*/
int (*update_textures)(const struct vlc_gl_interop *interop,
uint32_t textures[], const int32_t tex_width[],
const int32_t tex_height[], picture_t *pic,
const size_t plane_offsets[]);
/**
* Callback to retrieve the transform matrix to apply to texture coordinates
*
* This function pointer can be NULL. If it is set, it may return NULL.
*
* Otherwise, it must return a 2x3 matrix, as an array of 6 floats in
* column-major order.
*
* This transform matrix maps 2D homogeneous texture coordinates of the
* form (s, t, 1) with s and t in the inclusive range [0, 1] to the
* texture coordinate that should be used to sample that location from the
* texture.
*
* The returned pointer is owned by the converter module, and must not be
* freed before the module is closed.
*
* \param interop the OpenGL interop
* \return a 2x3 transformation matrix (possibly NULL)
*/
const float *
(*get_transform_matrix)(const struct vlc_gl_interop *interop);
/**
* Called before the interop is destroyed
*
* This function pointer can be NULL.
*
* \param interop the OpenGL interop
*/
void (*close)(struct vlc_gl_interop *interop);
};
struct vlc_gl_interop {
vlc_object_t obj;
module_t *module;
vlc_gl_t *gl;
uint32_t tex_target;
/* Input format
*
* This is the format of the pictures received from the core.
*
* It can be modified from the module open function to request changes from
* the core.
*/
video_format_t fmt_in;
/* Output format
*
* This is the format of the pictures exposed by the interop to the sampler.
*
* It may differ from the input format:
* - the orientation may be vertically flipped
* - the chroma contains the "software" chroma if the input chroma is opaque
* - the chroma may also be changed internally to a fallback (see
* opengl_interop_generic_init())
*/
video_format_t fmt_out;
/* Pointer to decoder video context, set by the caller (can be NULL) */
struct vlc_video_context *vctx;
/* Set to true if textures are generated from pf_update() */
bool handle_texs_gen;
/* Initialized by the interop */
struct vlc_gl_tex_cfg {
/*
* Texture scale factor, cannot be 0.
* In 4:2:0, 1/1 for the Y texture and 1/2 for the UV texture(s)
*/
vlc_rational_t w;
vlc_rational_t h;
int32_t internal;
uint32_t format;
uint32_t type;
} texs[PICTURE_PLANE_MAX];
unsigned tex_count;
void *priv;
const struct vlc_gl_interop_ops *ops;
/* Set by the caller to opengl_interop_init_impl().
* This avoids each module to link against opengl_interop_init_impl()
* directly. */
int
(*init)(struct vlc_gl_interop *interop, uint32_t tex_target,
vlc_fourcc_t chroma, video_color_space_t yuv_space);
};
#endif
......@@ -58,12 +58,18 @@ typedef struct {
CUcontext cuConverterCtx;
CUgraphicsResource cu_res[PICTURE_PLANE_MAX]; // Y, UV for NV12/P010
CUarray mappedArray[PICTURE_PLANE_MAX];
struct {
PFNGLBINDTEXTUREPROC BindTexture;
PFNGLGETERRORPROC GetError;
PFNGLTEXIMAGE2DPROC TexImage2D;
} gl;
} converter_sys_t;
#define CALL_CUDA(func, ...) CudaCheckErr(VLC_OBJECT(interop->gl), devsys->cudaFunctions, devsys->cudaFunctions->func(__VA_ARGS__), #func)
static int tc_nvdec_gl_allocate_texture(const struct vlc_gl_interop *interop, GLuint *textures,
const GLsizei *tex_width, const GLsizei *tex_height)
static int tc_nvdec_gl_allocate_texture(const struct vlc_gl_interop *interop, uint32_t textures[],
const int32_t tex_width[], const int32_t tex_height[])
{
converter_sys_t *p_sys = interop->priv;
vlc_decoder_device *device = p_sys->device;
......@@ -76,11 +82,11 @@ static int tc_nvdec_gl_allocate_texture(const struct vlc_gl_interop *interop, GL
for (unsigned i = 0; i < interop->tex_count; i++)
{
interop->vt->BindTexture(interop->tex_target, textures[i]);
interop->vt->TexImage2D(interop->tex_target, 0, interop->texs[i].internal,
p_sys->gl.BindTexture(interop->tex_target, textures[i]);
p_sys->gl.TexImage2D(interop->tex_target, 0, interop->texs[i].internal,
tex_width[i], tex_height[i], 0, interop->texs[i].format,
interop->texs[i].type, NULL);
if (interop->vt->GetError() != GL_NO_ERROR)
if (p_sys->gl.GetError() != GL_NO_ERROR)
{
msg_Err(interop->gl, "could not alloc PBO buffers");
return VLC_EGENERIC;
......@@ -92,7 +98,7 @@ static int tc_nvdec_gl_allocate_texture(const struct vlc_gl_interop *interop, GL
result = CALL_CUDA(cuGraphicsSubResourceGetMappedArray, &p_sys->mappedArray[i], p_sys->cu_res[i], 0, 0);
result = CALL_CUDA(cuGraphicsUnmapResources, 1, &p_sys->cu_res[i], 0);
interop->vt->BindTexture(interop->tex_target, 0);
p_sys->gl.BindTexture(interop->tex_target, 0);
}
CALL_CUDA(cuCtxPopCurrent, NULL);
......@@ -100,8 +106,8 @@ static int tc_nvdec_gl_allocate_texture(const struct vlc_gl_interop *interop, GL
}
static int
tc_nvdec_gl_update(const struct vlc_gl_interop *interop, GLuint textures[],
GLsizei const tex_widths[], GLsizei const tex_heights[],
tc_nvdec_gl_update(const struct vlc_gl_interop *interop, uint32_t textures[],
int32_t const tex_widths[], int32_t const tex_heights[],
picture_t *pic, size_t const plane_offsets[])
{
VLC_UNUSED(plane_offsets);
......@@ -167,6 +173,19 @@ static int Open(vlc_object_t *obj)
vlc_decoder_device_Release(device);
return VLC_ENOMEM;
}
p_sys->gl.BindTexture =
vlc_gl_GetProcAddress(interop->gl, "glBindTexture");
assert(p_sys->gl.BindTexture);
p_sys->gl.GetError =
vlc_gl_GetProcAddress(interop->gl, "glGetError");
assert(p_sys->gl.GetError);
p_sys->gl.TexImage2D =
vlc_gl_GetProcAddress(interop->gl, "glTexImage2D");
assert(p_sys->gl.TexImage2D);
for (size_t i=0; i < ARRAY_SIZE(p_sys->cu_res); i++)
p_sys->cu_res[i] = NULL;
p_sys->cuConverterCtx = NULL;
......
......@@ -209,7 +209,7 @@ static int Open( vlc_object_t *obj )
goto gl_api_failure;
}
sys->interop = vlc_gl_interop_New(sys->gl, api, filter->vctx_in,
sys->interop = vlc_gl_interop_New(sys->gl, filter->vctx_in,
&filter->fmt_in.video);
if (!sys->interop)
{
......
......@@ -23,6 +23,7 @@
#endif
#include <vlc_common.h>
#include <vlc_picture.h>
#include "importer_priv.h"
......@@ -204,8 +205,6 @@ vlc_gl_importer_New(struct vlc_gl_interop *interop)
return NULL;
importer->interop = interop;
importer->api = interop->api;
importer->vt = &interop->api->vt;
importer->mtx_transform_defined = false;
importer->pic_mtx_defined = false;
......@@ -227,6 +226,11 @@ vlc_gl_importer_New(struct vlc_gl_interop *interop)
InitOrientationMatrix(importer->mtx_orientation, glfmt->fmt.orientation);
/* OpenGL ES 2 includes support for non-power of 2 textures by specification. */
bool supports_npot = interop->gl->api_type == VLC_OPENGL_ES2
|| vlc_gl_HasExtension(interop->gl, "GL_ARB_texture_non_power_of_two")
|| vlc_gl_HasExtension(interop->gl, "GL_APPLE_texture_2D_limited_npot");
/* Texture size */
for (unsigned j = 0; j < interop->tex_count; j++) {
GLsizei w = interop->fmt_out.i_visible_width * interop->texs[j].w.num
......@@ -235,7 +239,7 @@ vlc_gl_importer_New(struct vlc_gl_interop *interop)
/ interop->texs[j].h.den;
glfmt->visible_widths[j] = w;
glfmt->visible_heights[j] = h;
if (interop->api->supports_npot) {
if (supports_npot) {
glfmt->tex_widths[j] = w;
glfmt->tex_heights[j] = h;
} else {
......@@ -263,10 +267,12 @@ void
vlc_gl_importer_Delete(struct vlc_gl_importer *importer)
{
struct vlc_gl_interop *interop = importer->interop;
if (interop && !interop->handle_texs_gen)
{
const opengl_vtable_t *vt = interop->vt;
vt->DeleteTextures(interop->tex_count, importer->pic.textures);
void (*DeleteTextures)(uint32_t, uint32_t*) =
vlc_gl_GetProcAddress(interop->gl, "glDeleteTextures");
(*DeleteTextures)(interop->tex_count, importer->pic.textures);
}
free(importer);
......
......@@ -21,18 +21,14 @@
#ifndef VLC_GL_IMPORTER_H
#define VLC_GL_IMPORTER_H
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_picture.h>
#include "interop.h"
typedef struct picture_t picture_t;
/**
* An importer uses an interop to convert picture_t to a valid vlc_gl_picture,
* with all necessary transformations computed.
*/
struct vlc_gl_importer;
struct vlc_gl_interop;
struct vlc_gl_importer *
vlc_gl_importer_New(struct vlc_gl_interop *interop);
......
......@@ -30,27 +30,51 @@
#include "interop_sw.h"
#include "vout_helper.h"
struct vlc_gl_interop_private
{
struct vlc_gl_interop interop;
#define OPENGL_VTABLE_F(X) \
X(PFNGLDELETETEXTURESPROC, DeleteTextures) \
X(PFNGLGENTEXTURESPROC, GenTextures) \
X(PFNGLBINDTEXTUREPROC, BindTexture) \
X(PFNGLTEXIMAGE2DPROC, TexImage2D) \
X(PFNGLTEXENVFPROC, TexEnvf) \
X(PFNGLTEXPARAMETERFPROC, TexParameterf) \
X(PFNGLTEXPARAMETERIPROC, TexParameteri) \
X(PFNGLGETERRORPROC, GetError) \
X(PFNGLGETTEXLEVELPARAMETERIVPROC, GetTexLevelParameteriv) \
struct {
#define DECLARE_SYMBOL(type, name) type name;
OPENGL_VTABLE_F(DECLARE_SYMBOL)
} gl;
};
int
vlc_gl_interop_GenerateTextures(const struct vlc_gl_interop *interop,
const GLsizei *tex_width,
const GLsizei *tex_height, GLuint *textures)
{
interop->vt->GenTextures(interop->tex_count, textures);
struct vlc_gl_interop_private *priv =
container_of(interop, struct vlc_gl_interop_private, interop);
priv->gl.GenTextures(interop->tex_count, textures);
for (unsigned i = 0; i < interop->tex_count; i++)
{
interop->vt->BindTexture(interop->tex_target, textures[i]);
priv->gl.BindTexture(interop->tex_target, textures[i]);
#if !defined(USE_OPENGL_ES2)
/* Set the texture parameters */
interop->vt->TexParameterf(interop->tex_target, GL_TEXTURE_PRIORITY, 1.0);
interop->vt->TexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
priv->gl.TexParameterf(interop->tex_target, GL_TEXTURE_PRIORITY, 1.0);
priv->gl.TexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
#endif
interop->vt->TexParameteri(interop->tex_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
interop->vt->TexParameteri(interop->tex_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
interop->vt->TexParameteri(interop->tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
interop->vt->TexParameteri(interop->tex_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
priv->gl.TexParameteri(interop->tex_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
priv->gl.TexParameteri(interop->tex_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
priv->gl.TexParameteri(interop->tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
priv->gl.TexParameteri(interop->tex_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
if (interop->ops->allocate_textures != NULL)
......@@ -58,7 +82,7 @@ vlc_gl_interop_GenerateTextures(const struct vlc_gl_interop *interop,
int ret = interop->ops->allocate_textures(interop, textures, tex_width, tex_height);
if (ret != VLC_SUCCESS)
{
interop->vt->DeleteTextures(interop->tex_count, textures);
priv->gl.DeleteTextures(interop->tex_count, textures);
memset(textures, 0, interop->tex_count * sizeof(GLuint));
return ret;
}
......@@ -70,15 +94,21 @@ void
vlc_gl_interop_DeleteTextures(const struct vlc_gl_interop *interop,
GLuint *textures)
{
interop->vt->DeleteTextures(interop->tex_count, textures);
struct vlc_gl_interop_private *priv =
container_of(interop, struct vlc_gl_interop_private, interop);
priv->gl.DeleteTextures(interop->tex_count, textures);
memset(textures, 0, interop->tex_count * sizeof(GLuint));
}
static int GetTexFormatSize(const opengl_vtable_t *vt, int target,
static int GetTexFormatSize(struct vlc_gl_interop *interop, int target,
int tex_format, int tex_internal, int tex_type)
{
GL_ASSERT_NOERROR(vt);
if (!vt->GetTexLevelParameteriv)
struct vlc_gl_interop_private *priv =
container_of(interop, struct vlc_gl_interop_private, interop);
GL_ASSERT_NOERROR(&priv->gl);
if (!priv->gl.GetTexLevelParameteriv)
return -1;
GLint tex_param_size;
......@@ -100,16 +130,16 @@ static int GetTexFormatSize(const opengl_vtable_t *vt, int target,
}
GLuint texture;
vt->GenTextures(1, &texture);
vt->BindTexture(target, texture);
vt->TexImage2D(target, 0, tex_internal, 64, 64, 0, tex_format, tex_type, NULL);
priv->gl.GenTextures(1, &texture);
priv->gl.BindTexture(target, texture);
priv->gl.TexImage2D(target, 0, tex_internal, 64, 64, 0, tex_format, tex_type, NULL);
GLint size = 0;
vt->GetTexLevelParameteriv(target, 0, tex_param_size, &size);
priv->gl.GetTexLevelParameteriv(target, 0, tex_param_size, &size);
vt->DeleteTextures(1, &texture);
priv->gl.DeleteTextures(1, &texture);
bool has_error = false;
while (vt->GetError() != GL_NO_ERROR)
while (priv->gl.GetError() != GL_NO_ERROR)
has_error = true;
if (has_error)
......@@ -136,7 +166,7 @@ interop_yuv_base_init(struct vlc_gl_interop *interop, GLenum tex_target,
GLint oneplane_texfmt, oneplane16_texfmt,
twoplanes_texfmt, twoplanes16_texfmt;
if (vlc_gl_StrHasToken(interop->api->extensions, "GL_ARB_texture_rg"))
if (vlc_gl_HasExtension(interop->gl, "GL_ARB_texture_rg"))
{
oneplane_texfmt = GL_RED;
oneplane16_texfmt = GL_R16;
......@@ -153,7 +183,7 @@ interop_yuv_base_init(struct vlc_gl_interop *interop, GLenum tex_target,
if (desc->pixel_size == 2)
{
if (GetTexFormatSize(interop->vt, tex_target, oneplane_texfmt,
if (GetTexFormatSize(interop, tex_target, oneplane_texfmt,
oneplane16_texfmt, GL_UNSIGNED_SHORT) != 16)
return VLC_EGENERIC;
}
......@@ -208,7 +238,7 @@ interop_yuv_base_init(struct vlc_gl_interop *interop, GLenum tex_target,
else if (desc->pixel_size == 2)
{
if (twoplanes16_texfmt == 0
|| GetTexFormatSize(interop->vt, tex_target, twoplanes_texfmt,
|| GetTexFormatSize(interop, tex_target, twoplanes_texfmt,
twoplanes16_texfmt, GL_UNSIGNED_SHORT) != 16)
return VLC_EGENERIC;
interop->texs[0] = (struct vlc_gl_tex_cfg) {
......@@ -283,7 +313,7 @@ interop_rgb_base_init(struct vlc_gl_interop *interop, GLenum tex_target,
};
break;
case VLC_CODEC_BGRA: {
if (GetTexFormatSize(interop->vt, tex_target, GL_BGRA, GL_RGBA,
if (GetTexFormatSize(interop, tex_target, GL_BGRA, GL_RGBA,
GL_UNSIGNED_BYTE) != 32)
return VLC_EGENERIC;
interop->texs[0] = (struct vlc_gl_tex_cfg) {
......@@ -336,23 +366,22 @@ opengl_interop_init_impl(struct vlc_gl_interop *interop, GLenum tex_target,
}
struct vlc_gl_interop *
vlc_gl_interop_New(struct vlc_gl_t *gl, const struct vlc_gl_api *api,
vlc_video_context *context, const video_format_t *fmt)
vlc_gl_interop_New(struct vlc_gl_t *gl, vlc_video_context *context,
const video_format_t *fmt)
{
struct vlc_gl_interop *interop = vlc_object_create(gl, sizeof(*interop));
if (!interop)
struct vlc_gl_interop_private *priv = vlc_object_create(gl, sizeof *priv);
if (priv == NULL)
return NULL;
struct vlc_gl_interop *interop = &priv->interop;
interop->init = opengl_interop_init_impl;
interop->ops = NULL;
interop->fmt_out = interop->fmt_in = *fmt;
interop->gl = gl;
/* this is the only allocated field, and we don't need it */
interop->fmt_out.p_palette = interop->fmt_in.p_palette = NULL;
interop->gl = gl;
interop->api = api;
interop->vt = &api->vt;
const vlc_chroma_description_t *desc =
vlc_fourcc_GetChromaDescription(fmt->i_chroma);
......@@ -362,6 +391,11 @@ vlc_gl_interop_New(struct vlc_gl_t *gl, const struct vlc_gl_api *api,
return NULL;
}
#define LOAD_SYMBOL(type, name) \
priv->gl.name = vlc_gl_GetProcAddress(interop->gl, "gl" # name);
OPENGL_VTABLE_F(LOAD_SYMBOL);
#undef LOAD_SYMBOL
if (desc->plane_count == 0)
{
/* Opaque chroma: load a module to handle it */
......@@ -378,6 +412,7 @@ vlc_gl_interop_New(struct vlc_gl_t *gl, const struct vlc_gl_api *api,
goto error;
}
return interop;
error:
......@@ -386,22 +421,25 @@ error:
}
struct vlc_gl_interop *
vlc_gl_interop_NewForSubpictures(struct vlc_gl_t *gl,
const struct vlc_gl_api *api)
vlc_gl_interop_NewForSubpictures(struct vlc_gl_t *gl)
{
struct vlc_gl_interop *interop = vlc_object_create(gl, sizeof(*interop));
if (!interop)
struct vlc_gl_interop_private *priv = vlc_object_create(gl, sizeof *priv);
if (priv == NULL)
return NULL;
struct vlc_gl_interop *interop = &priv->interop;
interop->init = opengl_interop_init_impl;
interop->ops = NULL;
interop->gl = gl;
interop->api = api;
interop->vt = &api->vt;
video_format_Init(&interop->fmt_in, VLC_CODEC_RGB32);
interop->fmt_out = interop->fmt_in;
#define LOAD_SYMBOL(type, name) \
priv->gl.name = vlc_gl_GetProcAddress(interop->gl, "gl" # name);
OPENGL_VTABLE_F(LOAD_SYMBOL);
#undef LOAD_SYMBOL
int ret = opengl_interop_generic_init(interop, false);
if (ret != VLC_SUCCESS)
{
......
......@@ -18,161 +18,23 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifndef VLC_GL_INTEROP_H
#define VLC_GL_INTEROP_H
#ifndef VLC_GL_INTEROP_PRIV_H
#define VLC_GL_INTEROP_PRIV_H
#include <vlc_common.h>
#include <vlc_opengl.h>
#include <vlc_picture.h>
#include <vlc_picture_pool.h>
#include <vlc_opengl_interop.h>
#include "gl_common.h"
struct vlc_gl_interop;
struct vlc_gl_interop_ops {
/**
* Callback to allocate data for bound textures
*
* This function pointer can be NULL. Software converters should call
* glTexImage2D() to allocate textures data (it will be deallocated by the
* caller when calling glDeleteTextures()). Won't be called if
* handle_texs_gen is true.
*
* \param interop the OpenGL interop
* \param textures array of textures to bind (one per plane)
* \param tex_width array of tex width (one per plane)
* \param tex_height array of tex height (one per plane)
* \return VLC_SUCCESS or a VLC error
*/
int
(*allocate_textures)(const struct vlc_gl_interop *interop,
GLuint textures[], const GLsizei tex_width[],
const GLsizei tex_height[]);
/**
* Callback to update a picture
*
* This function pointer cannot be NULL. The implementation should upload
* every planes of the picture.
*
* \param interop the OpenGL interop
* \param textures array of textures to bind (one per plane)
* \param tex_width array of tex width (one per plane)
* \param tex_height array of tex height (one per plane)
* \param pic picture to update
* \param plane_offset offsets of each picture planes to read data from
* (one per plane, can be NULL)
* \return VLC_SUCCESS or a VLC error
*/
int
(*update_textures)(const struct vlc_gl_interop *interop,
GLuint textures[], const GLsizei tex_width[],
const GLsizei tex_height[], picture_t *pic,
const size_t plane_offsets[]);
/**
* Callback to retrieve the transform matrix to apply to texture coordinates
*
* This function pointer can be NULL. If it is set, it may return NULL.
*
* Otherwise, it must return a 2x3 matrix, as an array of 6 floats in
* column-major order.
*
* This transform matrix maps 2D homogeneous texture coordinates of the
* form (s, t, 1) with s and t in the inclusive range [0, 1] to the
* texture coordinate that should be used to sample that location from the
* texture.
*
* The returned pointer is owned by the converter module, and must not be
* freed before the module is closed.
*
* \param interop the OpenGL interop
* \return a 2x3 transformation matrix (possibly NULL)
*/
const float *
(*get_transform_matrix)(const struct vlc_gl_interop *interop);
/**
* Called before the interop is destroyed
*
* This function pointer can be NULL.
*
* \param interop the OpenGL interop
*/
void
(*close)(struct vlc_gl_interop *interop);
};
struct vlc_gl_interop {
vlc_object_t obj;
module_t *module;
vlc_gl_t *gl;
const struct vlc_gl_api *api;
const opengl_vtable_t *vt; /* for convenience, same as &api->vt */
GLenum tex_target;
/* Input format
*
* This is the format of the pictures received from the core.
*
* It can be modified from the module open function to request changes from
* the core.
*/
video_format_t fmt_in;
/* Output format
*
* This is the format of the pictures exposed by the interop to the sampler.
*
* It may differ from the input format:
* - the orientation may be vertically flipped
* - the chroma contains the "software" chroma if the input chroma is opaque
* - the chroma may also be changed internally to a fallback (see
* opengl_interop_generic_init())
*/
video_format_t fmt_out;
/* Pointer to decoder video context, set by the caller (can be NULL) */
vlc_video_context *vctx;
/* Set to true if textures are generated from pf_update() */
bool handle_texs_gen;
/* Initialized by the interop */
struct vlc_gl_tex_cfg {
/*
* Texture scale factor, cannot be 0.
* In 4:2:0, 1/1 for the Y texture and 1/2 for the UV texture(s)
*/
vlc_rational_t w;
vlc_rational_t h;
GLint internal;
GLenum format;
GLenum type;
} texs[PICTURE_PLANE_MAX];
unsigned tex_count;
void *priv;
const struct vlc_gl_interop_ops *ops;
/* Set by the caller to opengl_interop_init_impl().
* This avoids each module to link against opengl_interop_init_impl()
* directly. */
int
(*init)(struct vlc_gl_interop *interop, GLenum tex_target,
vlc_fourcc_t chroma, video_color_space_t yuv_space);
};
struct vlc_gl_interop *
vlc_gl_interop_New(struct vlc_gl_t *gl, const struct vlc_gl_api *api,
vlc_video_context *context, const video_format_t *fmt);
vlc_gl_interop_New(struct vlc_gl_t *gl, vlc_video_context *context,
const video_format_t *fmt);
struct vlc_gl_interop *
vlc_gl_interop_NewForSubpictures(struct vlc_gl_t *gl,
const struct vlc_gl_api *api);
vlc_gl_interop_NewForSubpictures(struct vlc_gl_t *gl);
void
vlc_gl_interop_Delete(struct vlc_gl_interop *interop);
......
......@@ -40,6 +40,12 @@ struct priv
bool stex_attached;
struct vlc_asurfacetexture *previous_texture;
picture_t *current_picture;
struct {
PFNGLACTIVETEXTUREPROC ActiveTexture;
PFNGLBINDTEXTUREPROC BindTexture;
PFNGLGENTEXTURESPROC GenTextures;
} gl;
};
static void
......@@ -74,8 +80,8 @@ ReductMatrix(float *mtx_2x3, const float *mtx_4x4)
}
static int
tc_anop_allocate_textures(const struct vlc_gl_interop *interop, GLuint *textures,
const GLsizei *tex_width, const GLsizei *tex_height)
tc_anop_allocate_textures(const struct vlc_gl_interop *interop, uint32_t textures[],
const int32_t tex_width[], const int32_t tex_height[])
{
(void) tex_width; (void) tex_height;
struct priv *priv = interop->priv;
......@@ -85,8 +91,8 @@ tc_anop_allocate_textures(const struct vlc_gl_interop *interop, GLuint *textures
}
static int
tc_anop_update(struct vlc_gl_interop *interop, GLuint *textures,
const GLsizei *tex_width, const GLsizei *tex_height,
tc_anop_update(struct vlc_gl_interop *interop, uint32_t textures[],
const int32_t tex_width[], const int32_t tex_height[],
picture_t *pic, const size_t *plane_offset)
{
struct priv *priv = interop->priv;
......@@ -119,7 +125,7 @@ tc_anop_update(struct vlc_gl_interop *interop, GLuint *textures,
SurfaceTexture_detachFromGLContext(previous_texture);
/* SurfaceTexture_detachFromGLContext will destroy the previous
* texture name, so we need to regenerate it. */
interop->api->vt.GenTextures(1, &textures[0]);
priv->gl.GenTextures(1, &textures[0]);
}
if (SurfaceTexture_attachToGLContext(texture, textures[0]) != 0)
......@@ -147,8 +153,8 @@ tc_anop_update(struct vlc_gl_interop *interop, GLuint *textures,
ReductMatrix(priv->mtx_2x3, mtx_4x4);
priv->transform_mtx = priv->mtx_2x3;
interop->vt->ActiveTexture(GL_TEXTURE0);
interop->vt->BindTexture(interop->tex_target, textures[0]);
priv->gl.ActiveTexture(GL_TEXTURE0);
priv->gl.BindTexture(interop->tex_target, textures[0]);
success:
if (previous_picture)
......@@ -191,8 +197,7 @@ Open(vlc_object_t *obj)
|| !interop->vctx)
return VLC_EGENERIC;
const char *extensions = interop->api->vt.GetString(GL_EXTENSIONS);
if (!vlc_gl_StrHasToken(extensions, "GL_OES_EGL_image_external"))
if (!vlc_gl_HasExtension(interop->gl, "GL_OES_EGL_image_external"))
{
msg_Warn(&interop->obj, "GL_OES_EGL_image_external is not available,"
" disabling android interop.");
......@@ -215,6 +220,14 @@ Open(vlc_object_t *obj)
priv->previous_texture = NULL;
priv->stex_attached = false;
#define LOAD_SYMBOL(name) \
priv->gl.name = vlc_gl_GetProcAddress(interop->gl, "gl" # name); \
assert(priv->gl.name != NULL);
LOAD_SYMBOL(ActiveTexture);
LOAD_SYMBOL(BindTexture);
LOAD_SYMBOL(GenTextures);
static const struct vlc_gl_interop_ops ops = {
.allocate_textures = tc_anop_allocate_textures,
.update_textures = tc_anop_update,
......
......@@ -45,13 +45,20 @@ struct priv
CGLContextObj gl_ctx;
#endif
picture_t *last_pic;
struct {
PFNGLACTIVETEXTUREPROC ActiveTexture;
PFNGLBINDTEXTUREPROC BindTexture;
PFNGLTEXPARAMETERIPROC TexParameteri;
PFNGLTEXPARAMETERFPROC TexParameterf;
} gl;
};
#if TARGET_OS_IPHONE
/* CVOpenGLESTextureCache version (ios) */
static int
tc_cvpx_update(const struct vlc_gl_interop *interop, GLuint *textures,
const GLsizei *tex_width, const GLsizei *tex_height,
tc_cvpx_update(const struct vlc_gl_interop *interop, uint32_t textures[],
const int32_t tex_width[], const int32_t tex_height[],
picture_t *pic, const size_t *plane_offset)
{
(void) plane_offset;
......@@ -93,12 +100,12 @@ tc_cvpx_update(const struct vlc_gl_interop *interop, GLuint *textures,
}
textures[i] = CVOpenGLESTextureGetName(cvtex);
interop->vt->BindTexture(interop->tex_target, textures[i]);
interop->vt->TexParameteri(interop->tex_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
interop->vt->TexParameteri(interop->tex_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
interop->vt->TexParameterf(interop->tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
interop->vt->TexParameterf(interop->tex_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
interop->vt->BindTexture(interop->tex_target, 0);
priv->gl.BindTexture(interop->tex_target, textures[i]);
priv->gl.TexParameteri(interop->tex_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
priv->gl.TexParameteri(interop->tex_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
priv->gl.TexParameterf(interop->tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
priv->gl.TexParameterf(interop->tex_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
priv->gl.BindTexture(interop->tex_target, 0);
priv->last_cvtexs[i] = cvtex;
}
......@@ -108,8 +115,8 @@ tc_cvpx_update(const struct vlc_gl_interop *interop, GLuint *textures,
#else
/* IOSurface version (macos) */
static int
tc_cvpx_update(const struct vlc_gl_interop *interop, GLuint *textures,
const GLsizei *tex_width, const GLsizei *tex_height,
tc_cvpx_update(const struct vlc_gl_interop *interop, uint32_t textures[],
const int32_t tex_width[], const int32_t tex_height[],
picture_t *pic, const size_t *plane_offset)
{
(void) plane_offset;
......@@ -121,8 +128,8 @@ tc_cvpx_update(const struct vlc_gl_interop *interop, GLuint *textures,
for (unsigned i = 0; i < interop->tex_count; ++i)
{
interop->vt->ActiveTexture(GL_TEXTURE0 + i);
interop->vt->BindTexture(interop->tex_target, textures[i]);
priv->gl.ActiveTexture(GL_TEXTURE0 + i);
priv->gl.BindTexture(interop->tex_target, textures[i]);
CGLError err =
CGLTexImageIOSurface2D(priv->gl_ctx, interop->tex_target,
......@@ -184,6 +191,15 @@ Open(vlc_object_t *obj)
if (unlikely(priv == NULL))
return VLC_ENOMEM;
#define LOAD_FUNCTION(name) \
priv->gl.name = vlc_gl_GetProcAddress(interop->gl, "gl" # name); \
assert(priv->gl.name != NULL)
LOAD_FUNCTION(ActiveTexture);
LOAD_FUNCTION(BindTexture);
LOAD_FUNCTION(TexParameteri);
LOAD_FUNCTION(TexParameterf);
#if TARGET_OS_IPHONE
const GLenum tex_target = GL_TEXTURE_2D;
......
......@@ -97,8 +97,8 @@ struct glpriv
};
static int
GLConvUpdate(const struct vlc_gl_interop *interop, GLuint *textures,
const GLsizei *tex_width, const GLsizei *tex_height,
GLConvUpdate(const struct vlc_gl_interop *interop, uint32_t textures[],
const int32_t tex_width[], const int32_t tex_height[],
picture_t *pic, const size_t *plane_offset)
{
VLC_UNUSED(textures); VLC_UNUSED(tex_width); VLC_UNUSED(tex_height); VLC_UNUSED(plane_offset);
......@@ -163,8 +163,8 @@ GLConvUpdate(const struct vlc_gl_interop *interop, GLuint *textures,
}
static int
GLConvAllocateTextures(const struct vlc_gl_interop *interop, GLuint *textures,
const GLsizei *tex_width, const GLsizei *tex_height)
GLConvAllocateTextures(const struct vlc_gl_interop *interop, uint32_t textures[],
const int32_t tex_width[], const int32_t tex_height[])
{
VLC_UNUSED(tex_width); VLC_UNUSED(tex_height);
struct glpriv *priv = interop->priv;
......
......@@ -48,6 +48,27 @@ struct priv
picture_t *display_pics[PBO_DISPLAY_COUNT];
size_t display_idx;
} pbo;
#define OPENGL_VTABLE_F(X) \
X(PFNGLGETERRORPROC, GetError) \
X(PFNGLGETINTEGERVPROC, GetIntegerv) \
X(PFNGLGETSTRINGPROC, GetString) \
\
X(PFNGLACTIVETEXTUREPROC, ActiveTexture) \
X(PFNGLBINDTEXTUREPROC, BindTexture) \
X(PFNGLTEXIMAGE2DPROC, TexImage2D) \
X(PFNGLTEXSUBIMAGE2DPROC, TexSubImage2D) \
\
X(PFNGLBINDBUFFERPROC, BindBuffer) \
X(PFNGLBUFFERDATAPROC, BufferData) \
X(PFNGLBUFFERSUBDATAPROC, BufferSubData) \
X(PFNGLDELETEBUFFERSPROC, DeleteBuffers) \
X(PFNGLGENBUFFERSPROC, GenBuffers) \
X(PFNGLPIXELSTOREIPROC, PixelStorei)
struct {
#define DECLARE_SYMBOL(type, name) type name;
OPENGL_VTABLE_F(DECLARE_SYMBOL)
} gl;
};
static void
......@@ -63,6 +84,7 @@ pbo_picture_destroy(picture_t *pic)
static picture_t *
pbo_picture_create(const struct vlc_gl_interop *interop)
{
const struct priv *priv = interop->priv;
picture_sys_t *picsys = calloc(1, sizeof(*picsys));
if (unlikely(picsys == NULL))
return NULL;
......@@ -78,8 +100,8 @@ pbo_picture_create(const struct vlc_gl_interop *interop)
return NULL;
}
interop->vt->GenBuffers(pic->i_planes, picsys->buffers);
picsys->DeleteBuffers = interop->vt->DeleteBuffers;
priv->gl.GenBuffers(pic->i_planes, picsys->buffers);
picsys->DeleteBuffers = priv->gl.DeleteBuffers;
/* XXX: needed since picture_NewFromResource override pic planes */
if (picture_Setup(pic, &interop->fmt_out))
......@@ -109,20 +131,21 @@ pbo_picture_create(const struct vlc_gl_interop *interop)
static int
pbo_data_alloc(const struct vlc_gl_interop *interop, picture_t *pic)
{
const struct priv *priv = interop->priv;
picture_sys_t *picsys = pic->p_sys;
interop->vt->GetError();
priv->gl.GetError();
for (int i = 0; i < pic->i_planes; ++i)
{
interop->vt->BindBuffer(GL_PIXEL_UNPACK_BUFFER, picsys->buffers[i]);
interop->vt->BufferData(GL_PIXEL_UNPACK_BUFFER, picsys->bytes[i], NULL,
priv->gl.BindBuffer(GL_PIXEL_UNPACK_BUFFER, picsys->buffers[i]);
priv->gl.BufferData(GL_PIXEL_UNPACK_BUFFER, picsys->bytes[i], NULL,
GL_DYNAMIC_DRAW);
if (interop->vt->GetError() != GL_NO_ERROR)
if (priv->gl.GetError() != GL_NO_ERROR)
{
msg_Err(interop->gl, "could not alloc PBO buffers");
interop->vt->DeleteBuffers(i, picsys->buffers);
priv->gl.DeleteBuffers(i, picsys->buffers);
return VLC_EGENERIC;
}
}
......@@ -145,7 +168,7 @@ pbo_pics_alloc(const struct vlc_gl_interop *interop)
}
/* turn off pbo */
interop->vt->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
priv->gl.BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
return VLC_SUCCESS;
error:
......@@ -155,8 +178,8 @@ error:
}
static int
tc_pbo_update(const struct vlc_gl_interop *interop, GLuint *textures,
const GLsizei *tex_width, const GLsizei *tex_height,
tc_pbo_update(const struct vlc_gl_interop *interop, uint32_t textures[],
const int32_t tex_width[], const int32_t tex_height[],
picture_t *pic, const size_t *plane_offset)
{
(void) plane_offset; assert(plane_offset == NULL);
......@@ -170,35 +193,36 @@ tc_pbo_update(const struct vlc_gl_interop *interop, GLuint *textures,
{
GLsizeiptr size = pic->p[i].i_lines * pic->p[i].i_pitch;
const GLvoid *data = pic->p[i].p_pixels;
interop->vt->BindBuffer(GL_PIXEL_UNPACK_BUFFER,
priv->gl.BindBuffer(GL_PIXEL_UNPACK_BUFFER,
p_sys->buffers[i]);
interop->vt->BufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, size, data);
priv->gl.BufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, size, data);
interop->vt->ActiveTexture(GL_TEXTURE0 + i);
interop->vt->BindTexture(interop->tex_target, textures[i]);
priv->gl.ActiveTexture(GL_TEXTURE0 + i);
priv->gl.BindTexture(interop->tex_target, textures[i]);
interop->vt->PixelStorei(GL_UNPACK_ROW_LENGTH, pic->p[i].i_pitch
priv->gl.PixelStorei(GL_UNPACK_ROW_LENGTH, pic->p[i].i_pitch
* tex_width[i] / (pic->p[i].i_visible_pitch ? pic->p[i].i_visible_pitch : 1));
interop->vt->TexSubImage2D(interop->tex_target, 0, 0, 0, tex_width[i], tex_height[i],
priv->gl.TexSubImage2D(interop->tex_target, 0, 0, 0, tex_width[i], tex_height[i],
interop->texs[i].format, interop->texs[i].type, NULL);
interop->vt->PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
priv->gl.PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
}
/* turn off pbo */
interop->vt->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
priv->gl.BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
return VLC_SUCCESS;
}
static int
tc_common_allocate_textures(const struct vlc_gl_interop *interop, GLuint *textures,
const GLsizei *tex_width, const GLsizei *tex_height)
tc_common_allocate_textures(const struct vlc_gl_interop *interop, uint32_t textures[],
const int32_t tex_width[], const int32_t tex_height[])
{
const struct priv *priv = interop->priv;
for (unsigned i = 0; i < interop->tex_count; i++)
{
interop->vt->BindTexture(interop->tex_target, textures[i]);
interop->vt->TexImage2D(interop->tex_target, 0, interop->texs[i].internal,
priv->gl.BindTexture(interop->tex_target, textures[i]);
priv->gl.TexImage2D(interop->tex_target, 0, interop->texs[i].internal,
tex_width[i], tex_height[i], 0, interop->texs[i].format,
interop->texs[i].type, NULL);
}
......@@ -207,7 +231,7 @@ tc_common_allocate_textures(const struct vlc_gl_interop *interop, GLuint *textur
static int
upload_plane(const struct vlc_gl_interop *interop, unsigned tex_idx,
GLsizei width, GLsizei height,
int32_t width, int32_t height,
unsigned pitch, unsigned visible_pitch, const void *pixels)
{
struct priv *priv = interop->priv;
......@@ -215,7 +239,7 @@ upload_plane(const struct vlc_gl_interop *interop, unsigned tex_idx,
GLenum tex_type = interop->texs[tex_idx].type;
/* This unpack alignment is the default, but setting it just in case. */
interop->vt->PixelStorei(GL_UNPACK_ALIGNMENT, 4);
priv->gl.PixelStorei(GL_UNPACK_ALIGNMENT, 4);
if (!priv->has_unpack_subimage)
{
......@@ -244,36 +268,37 @@ upload_plane(const struct vlc_gl_interop *interop, unsigned tex_idx,
source += pitch;
destination += visible_pitch;
}
interop->vt->TexSubImage2D(interop->tex_target, 0, 0, 0, width, height,
priv->gl.TexSubImage2D(interop->tex_target, 0, 0, 0, width, height,
tex_format, tex_type, priv->texture_temp_buf);
}
else
{
interop->vt->TexSubImage2D(interop->tex_target, 0, 0, 0, width, height,
priv->gl.TexSubImage2D(interop->tex_target, 0, 0, 0, width, height,
tex_format, tex_type, pixels);
}
}
else
{
interop->vt->PixelStorei(GL_UNPACK_ROW_LENGTH, pitch * width / (visible_pitch ? visible_pitch : 1));
interop->vt->TexSubImage2D(interop->tex_target, 0, 0, 0, width, height,
priv->gl.PixelStorei(GL_UNPACK_ROW_LENGTH, pitch * width / (visible_pitch ? visible_pitch : 1));
priv->gl.TexSubImage2D(interop->tex_target, 0, 0, 0, width, height,
tex_format, tex_type, pixels);
interop->vt->PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
priv->gl.PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
}
return VLC_SUCCESS;
}
static int
tc_common_update(const struct vlc_gl_interop *interop, GLuint *textures,
const GLsizei *tex_width, const GLsizei *tex_height,
tc_common_update(const struct vlc_gl_interop *interop, uint32_t textures[],
const int32_t tex_width[], const int32_t tex_height[],
picture_t *pic, const size_t *plane_offset)
{
const struct priv *priv = interop->priv;
int ret = VLC_SUCCESS;
for (unsigned i = 0; i < interop->tex_count && ret == VLC_SUCCESS; i++)
{
assert(textures[i] != 0);
interop->vt->ActiveTexture(GL_TEXTURE0 + i);
interop->vt->BindTexture(interop->tex_target, textures[i]);
priv->gl.ActiveTexture(GL_TEXTURE0 + i);
priv->gl.BindTexture(interop->tex_target, textures[i]);
const void *pixels = plane_offset != NULL ?
&pic->p[i].p_pixels[plane_offset[i]] :
pic->p[i].p_pixels;
......@@ -297,13 +322,24 @@ opengl_interop_generic_deinit(struct vlc_gl_interop *interop)
int
opengl_interop_generic_init(struct vlc_gl_interop *interop, bool allow_dr)
{
struct priv *priv = calloc(1, sizeof(struct priv));
if (unlikely(priv == NULL))
return VLC_ENOMEM;
#define LOAD_SYMBOL(type, name) \
priv->gl.name = vlc_gl_GetProcAddress(interop->gl, "gl" # name); \
assert(priv->gl.name != NULL);
OPENGL_VTABLE_F(LOAD_SYMBOL);
video_color_space_t space;
const vlc_fourcc_t *list;
if (vlc_fourcc_IsYUV(interop->fmt_in.i_chroma))
{
GLint max_texture_units = 0;
interop->vt->GetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_texture_units);
priv->gl.GetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_texture_units);
if (max_texture_units < 3)
return VLC_EGENERIC;
......@@ -364,34 +400,31 @@ interop_init:
video_format_FixRgb(&interop->fmt_out);
}
struct priv *priv = interop->priv = calloc(1, sizeof(struct priv));
if (unlikely(priv == NULL))
return VLC_ENOMEM;
static const struct vlc_gl_interop_ops ops = {
.allocate_textures = tc_common_allocate_textures,
.update_textures = tc_common_update,
.close = opengl_interop_generic_deinit,
};
interop->priv = priv;
interop->ops = &ops;
interop->fmt_in.i_chroma = i_chroma;
/* OpenGL or OpenGL ES2 with GL_EXT_unpack_subimage ext */
priv->has_unpack_subimage =
!interop->api->is_gles || vlc_gl_StrHasToken(interop->api->extensions, "GL_EXT_unpack_subimage");
priv->has_unpack_subimage = interop->gl->api_type == VLC_OPENGL
|| vlc_gl_HasExtension(interop->gl, "GL_EXT_unpack_subimage");
if (allow_dr && priv->has_unpack_subimage)
{
/* Ensure we do direct rendering / PBO with OpenGL 3.0 or higher. */
const unsigned char *ogl_version = interop->vt->GetString(GL_VERSION);
const unsigned char *ogl_version = priv->gl.GetString(GL_VERSION);
const bool glver_ok = strverscmp((const char *)ogl_version, "3.0") >= 0;
const bool has_pbo = glver_ok &&
(vlc_gl_StrHasToken(interop->api->extensions, "GL_ARB_pixel_buffer_object") ||
vlc_gl_StrHasToken(interop->api->extensions, "GL_EXT_pixel_buffer_object"));
(vlc_gl_HasExtension(interop->gl, "GL_ARB_pixel_buffer_object") ||
vlc_gl_HasExtension(interop->gl, "GL_EXT_pixel_buffer_object"));
const bool supports_pbo = has_pbo && interop->vt->BufferData
&& interop->vt->BufferSubData;
const bool supports_pbo = has_pbo && priv->gl.BufferData
&& priv->gl.BufferSubData;
if (supports_pbo && pbo_pics_alloc(interop) == VLC_SUCCESS)
{
static const struct vlc_gl_interop_ops pbo_ops = {
......
......@@ -71,6 +71,11 @@ struct priv
void (*destroyImageKHR)(EGLDisplay, EGLImage image);
} egl;
struct
{
PFNGLBINDTEXTUREPROC BindTexture;
} gl;
unsigned fourcc;
EGLint drm_fourccs[3];
......@@ -184,8 +189,8 @@ vaegl_init_fourcc(struct priv *priv, unsigned va_fourcc)
}
static int
tc_vaegl_update(const struct vlc_gl_interop *interop, GLuint *textures,
const GLsizei *tex_width, const GLsizei *tex_height,
tc_vaegl_update(const struct vlc_gl_interop *interop, uint32_t textures[],
const int32_t tex_width[], const int32_t tex_height[],
picture_t *pic, const size_t *plane_offset)
{
(void) plane_offset;
......@@ -255,7 +260,7 @@ tc_vaegl_update(const struct vlc_gl_interop *interop, GLuint *textures,
if (egl_images[i] == NULL)
goto error;
interop->vt->BindTexture(interop->tex_target, textures[i]);
priv->gl.BindTexture(interop->tex_target, textures[i]);
priv->glEGLImageTargetTexture2DOES(interop->tex_target, egl_images[i]);
}
......@@ -270,7 +275,7 @@ tc_vaegl_update(const struct vlc_gl_interop *interop, GLuint *textures,
if (egl_images[i] == NULL)
goto error;
interop->vt->BindTexture(interop->tex_target, textures[i]);
priv->gl.BindTexture(interop->tex_target, textures[i]);
priv->glEGLImageTargetTexture2DOES(interop->tex_target, egl_images[i]);
}
......@@ -441,7 +446,7 @@ Open(vlc_object_t *obj)
goto error;
}
if (!vlc_gl_StrHasToken(interop->api->extensions, "GL_OES_EGL_image"))
if (!vlc_gl_HasExtension(interop->gl, "GL_OES_EGL_image"))
goto error;
priv = interop->priv = calloc(1, sizeof(struct priv));
......@@ -500,6 +505,11 @@ Open(vlc_object_t *obj)
if (priv->glEGLImageTargetTexture2DOES == NULL)
goto error;
priv->gl.BindTexture =
vlc_gl_GetProcAddress(interop->gl, "glBindTexture");
if (priv->gl.BindTexture == NULL)
goto error;
priv->vadpy = dec_device->opaque;
assert(priv->vadpy != NULL);
......
......@@ -42,7 +42,7 @@
#define INTEROP_CALL(fct, ...) \
_##fct(__VA_ARGS__); \
{ \
GLenum ret = interop->vt->GetError(); \
GLenum ret = ((converter_sys_t*)interop->priv)->gl.GetError(); \
if (ret != GL_NO_ERROR) \
{ \
msg_Err(interop->gl, #fct " failed: 0x%x", ret); \
......@@ -62,11 +62,14 @@ static PFNGLVDPAUUNMAPSURFACESNVPROC _glVDPAUUnmapSurfacesNV;
typedef struct {
vlc_decoder_device *dec_device;
struct {
PFNGLGETERRORPROC GetError;
} gl;
} converter_sys_t;
static int
tc_vdpau_gl_update(const struct vlc_gl_interop *interop, GLuint textures[],
GLsizei const tex_widths[], GLsizei const tex_heights[],
tc_vdpau_gl_update(const struct vlc_gl_interop *interop, uint32_t textures[],
int32_t const tex_widths[], int32_t const tex_heights[],
picture_t *pic, size_t const plane_offsets[])
{
VLC_UNUSED(tex_widths);
......@@ -107,8 +110,10 @@ tc_vdpau_gl_update(const struct vlc_gl_interop *interop, GLuint textures[],
static void
Close(struct vlc_gl_interop *interop)
{
_glVDPAUFiniNV(); assert(interop->vt->GetError() == GL_NO_ERROR);
converter_sys_t *sys = interop->priv;
_glVDPAUFiniNV();
assert(sys->gl.GetError() == GL_NO_ERROR);
vlc_decoder_device *dec_device = sys->dec_device;
vlc_decoder_device_Release(dec_device);
}
......@@ -124,8 +129,7 @@ Open(vlc_object_t *obj)
|| (interop->fmt_in.i_chroma != VLC_CODEC_VDPAU_VIDEO_420
&& interop->fmt_in.i_chroma != VLC_CODEC_VDPAU_VIDEO_422
&& interop->fmt_in.i_chroma != VLC_CODEC_VDPAU_VIDEO_444)
|| !vlc_gl_StrHasToken(interop->api->extensions, "GL_NV_vdpau_interop")
|| interop->gl->surface->type != VOUT_WINDOW_TYPE_XID)
|| !vlc_gl_HasExtension(interop->gl, "GL_NV_vdpau_interop"))
{
vlc_decoder_device_Release(dec_device);
return VLC_EGENERIC;
......@@ -138,6 +142,8 @@ Open(vlc_object_t *obj)
return VLC_ENOMEM;
}
sys->dec_device = dec_device;
sys->gl.GetError = vlc_gl_GetProcAddress(interop->gl, "glGetError");
assert(sys->gl.GetError != NULL);
/* Request to change the input chroma to the core */
interop->fmt_in.i_chroma = VLC_CODEC_VDPAU_OUTPUT;
......
......@@ -133,7 +133,7 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
(GLint)fmt->i_height > max_tex_size)
ResizeFormatToGLMaxTexSize(fmt, max_tex_size);
vgl->interop = vlc_gl_interop_New(gl, api, context, fmt);
vgl->interop = vlc_gl_interop_New(gl, context, fmt);
if (!vgl->interop)
{
msg_Err(gl, "Could not create interop");
......@@ -203,7 +203,7 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
goto delete_filters;
}
vgl->sub_interop = vlc_gl_interop_NewForSubpictures(gl, api);
vgl->sub_interop = vlc_gl_interop_NewForSubpictures(gl);
if (!vgl->sub_interop)
{
msg_Err(gl, "Could not create sub interop");
......
......@@ -81,6 +81,7 @@ pluginsinclude_HEADERS = \
../include/vlc_network.h \
../include/vlc_objects.h \
../include/vlc_opengl.h \
../include/vlc_opengl_interop.h \
../include/vlc_picture.h \
../include/vlc_picture_fifo.h \
../include/vlc_picture_pool.h \
......
......@@ -710,6 +710,7 @@ vlc_gl_Create
vlc_gl_CreateOffscreen
vlc_gl_Release
vlc_gl_Hold
vlc_gl_HasExtension
vlc_gl_surface_Create
vlc_gl_surface_CheckSize
vlc_gl_surface_Destroy
......
......@@ -37,6 +37,13 @@ struct vlc_gl_priv_t
{
vlc_gl_t gl;
vlc_atomic_rc_t rc;
struct {
const uint8_t* (*GetString)(uint32_t);
const uint8_t* (*GetStringi)(uint32_t, uint32_t);
void (*GetIntegerv)(uint32_t, int32_t *);
uint32_t (*GetError)();
} vt;
};
static int vlc_gl_start(void *func, bool forced, va_list ap)
......@@ -84,6 +91,10 @@ vlc_gl_t *vlc_gl_Create(const struct vout_display_cfg *restrict cfg,
gl->api_type = api_type;
gl->surface = wnd;
gl->device = NULL;
glpriv->vt.GetString = NULL;
glpriv->vt.GetStringi = NULL;
glpriv->vt.GetIntegerv = NULL;
gl->module = vlc_module_load(gl, type, name, true, vlc_gl_start, gl,
cfg->display.width, cfg->display.height);
if (gl->module == NULL)
......@@ -179,6 +190,69 @@ void vlc_gl_Release(vlc_gl_t *gl)
vlc_object_delete(gl);
}
bool vlc_gl_HasExtension(vlc_gl_t *gl, const char *extension)
{
#define GL_NO_ERROR 0
#define GL_VERSION 0x1F02
#define GL_MAJOR_VERSION 0x821B
#define GL_EXTENSIONS 0x1F03
#define GL_NUM_EXTENSIONS 0x821D
struct vlc_gl_priv_t *glpriv = (struct vlc_gl_priv_t *)gl;
/* Cache the OpenGL function before checking. It's not done at OpenGL
* provider creation because the context might not be current, and it is
* not done at MakeCurrent because MakeCurrent is currently called at each
* frames, whereas vlc_gl_HasExtension can be called only during the
* client code initialization. */
if (glpriv->vt.GetString == NULL && glpriv->vt.GetStringi == NULL)
{
glpriv->vt.GetString = vlc_gl_GetProcAddress(gl, "glGetString");
glpriv->vt.GetIntegerv = vlc_gl_GetProcAddress(gl, "glGetIntegerv");
glpriv->vt.GetError = vlc_gl_GetProcAddress(gl, "glGetError");
int32_t version;
/* GL_MAJOR_VERSION is available in every OpenGL and GLES>=3.
* https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glGet.xhtml
* https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glGet.xhtml
* It will return a GL_INVALID_ENUM error on GLES<3
*/
glpriv->vt.GetIntegerv(GL_MAJOR_VERSION, &version);
uint32_t error = glpriv->vt.GetError();
if (error != GL_NO_ERROR)
version = 2;
/* Drain the errors before continuing. */
while (error != GL_NO_ERROR)
error = glpriv->vt.GetError();
/* glGetStringi is available in OpenGL>=3 and GLES>=3.
* https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glGetString.xhtml
* https://www.khronos.org/registry/OpenGL-Refpages/es3/html/glGetString.xhtml
*/
if (version >= 3)
glpriv->vt.GetStringi = vlc_gl_GetProcAddress(gl, "glGetStringi");
}
/* Fallback to legacy checking mode. */
if (glpriv->vt.GetStringi == NULL)
{
const uint8_t *extensions = glpriv->vt.GetString(GL_EXTENSIONS);
return vlc_gl_StrHasToken((const char *)extensions, extension);
}
/* Unfortunately, no order is defined by the standard, so just loop over
* the different extensions linearily. */
int32_t count = 0;
glpriv->vt.GetIntegerv(GL_NUM_EXTENSIONS, &count);
for (int i = 0; i < count; ++i)
{
const uint8_t *name = glpriv->vt.GetStringi(GL_EXTENSIONS, i);
if (strcmp((const char *)name, extension) == 0)
return true;
}
return false;
}
#include <vlc_vout_window.h>
typedef struct vlc_gl_surface
......