0019-ios2-vout-add-subpicture-rendering-in-the-zero-copy-.patch 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. From b446f7dfd3e2fbd981b8cbb075a255cf99a8984b Mon Sep 17 00:00:00 2001
  2. From: Adrien Maglo <magsoft@videolan.org>
  3. Date: Fri, 16 Sep 2016 14:00:21 +0200
  4. Subject: [PATCH 19/21] ios2 vout: add subpicture rendering in the zero copy
  5. pipeline
  6. ---
  7. modules/video_output/ios2.m | 338 +++++++++++++++++++++++++++++++++++++++-----
  8. 1 file changed, 304 insertions(+), 34 deletions(-)
  9. diff --git a/modules/video_output/ios2.m b/modules/video_output/ios2.m
  10. index 5e56ca5..6d4f1f1 100644
  11. --- a/modules/video_output/ios2.m
  12. +++ b/modules/video_output/ios2.m
  13. @@ -46,6 +46,7 @@
  14. #import <vlc_vout_display.h>
  15. #import <vlc_opengl.h>
  16. #import <vlc_dialog.h>
  17. +#import <vlc_memory.h>
  18. #import "opengl.h"
  19. /**
  20. @@ -110,6 +111,20 @@ static NSString *const fragmentShaderString = @" \
  21. } \
  22. ";
  23. +static NSString *const fragmentShaderRGBAString = @" \
  24. +varying highp vec2 texCoordVarying; \
  25. +precision mediump float; \
  26. +\
  27. +uniform sampler2D Texture; \
  28. +uniform vec4 FillColor; \
  29. +\
  30. +void main() \
  31. +{ \
  32. + gl_FragColor = texture2D(Texture, texCoordVarying) * FillColor; \
  33. +} \
  34. +";
  35. +
  36. +
  37. static NSString *const vertexShaderString = @" \
  38. attribute vec4 position; \
  39. attribute vec2 texCoord; \
  40. @@ -139,7 +154,7 @@ static void OpenglESSwap(vlc_gl_t *);
  41. static picture_pool_t *ZeroCopyPicturePool(vout_display_t *, unsigned);
  42. static void DestroyZeroCopyPoolPicture(picture_t *);
  43. -static void ZeroCopyClean(vout_display_t *vd, picture_t *pic, subpicture_t *subpicture);
  44. +static void ZeroCopyPrepare(vout_display_t *vd, picture_t *pic, subpicture_t *subpicture);
  45. static void ZeroCopyDisplay(vout_display_t *, picture_t *, subpicture_t *);
  46. /**
  47. @@ -178,6 +193,7 @@ vlc_module_end ()
  48. @property (readonly) EAGLContext* eaglContext;
  49. @property (readonly) BOOL isAppActive;
  50. @property GLuint shaderProgram;
  51. +@property GLuint shaderProgramSubpictures;
  52. - (id)initWithFrame:(CGRect)frame zeroCopy:(bool)zero_copy voutDisplay:(vout_display_t *)vd;
  53. @@ -191,6 +207,24 @@ vlc_module_end ()
  54. - (void)displayPixelBuffer:(CVPixelBufferRef)pixelBuffer;
  55. @end
  56. +typedef struct {
  57. + GLuint texture;
  58. + unsigned format;
  59. + unsigned type;
  60. + unsigned width;
  61. + unsigned height;
  62. +
  63. + float alpha;
  64. +
  65. + float top;
  66. + float left;
  67. + float bottom;
  68. + float right;
  69. +
  70. + float tex_width;
  71. + float tex_height;
  72. +} gl_region_t;
  73. +
  74. struct vout_display_sys_t
  75. {
  76. VLCOpenGLES2VideoView *glESView;
  77. @@ -205,8 +239,22 @@ struct vout_display_sys_t
  78. bool zero_copy;
  79. vout_display_place_t place;
  80. +
  81. + // Subpicture
  82. + int region_count;
  83. + gl_region_t *region;
  84. +
  85. + uint8_t *texture_temp_buf;
  86. + int texture_temp_buf_size;
  87. };
  88. +static inline int GetAlignedSize(unsigned size)
  89. +{
  90. + /* Return the smallest larger or equal power of 2 */
  91. + unsigned align = 1 << (8 * sizeof (unsigned) - clz(size));
  92. + return ((align >> 1) == size) ? size : align;
  93. +}
  94. +
  95. static void *OurGetProcAddress(vlc_gl_t *gl, const char *name)
  96. {
  97. VLC_UNUSED(gl);
  98. @@ -281,7 +329,7 @@ static int Open(vlc_object_t *this)
  99. if (sys->zero_copy) {
  100. vd->pool = ZeroCopyPicturePool;
  101. - vd->prepare = ZeroCopyClean;
  102. + vd->prepare = ZeroCopyPrepare;
  103. vd->display = ZeroCopyDisplay;
  104. } else {
  105. vd->pool = PicturePool;
  106. @@ -325,6 +373,15 @@ void Close (vlc_object_t *this)
  107. vout_display_sys_t *sys = vd->sys;
  108. @autoreleasepool {
  109. + glDeleteProgram(sys->glESView.shaderProgram);
  110. + glDeleteProgram(sys->glESView.shaderProgramSubpictures);
  111. +
  112. + for (int i = 0; i < sys->region_count; i++) {
  113. + if (sys->region[i].texture)
  114. + glDeleteTextures(1, &sys->region[i].texture);
  115. + }
  116. + free(sys->region);
  117. +
  118. if (sys->tapRecognizer) {
  119. [sys->tapRecognizer.view removeGestureRecognizer:sys->tapRecognizer];
  120. [sys->tapRecognizer release];
  121. @@ -356,7 +413,8 @@ void Close (vlc_object_t *this)
  122. picture_pool_Release(sys->picturePool);
  123. sys->picturePool = NULL;
  124. }
  125. -
  126. +
  127. + free(sys->texture_temp_buf);
  128. free(sys);
  129. }
  130. }
  131. @@ -548,11 +606,154 @@ static void DestroyZeroCopyPoolPicture(picture_t *picture)
  132. free(picture);
  133. }
  134. -static void ZeroCopyClean(vout_display_t *vd, picture_t *pic, subpicture_t *subpicture)
  135. +#define ALIGN(x, y) (((x) + ((y) - 1)) & ~((y) - 1))
  136. +static void Upload(vout_display_sys_t *sys,
  137. + int in_width, int in_height,
  138. + int in_full_width, int in_full_height,
  139. + int w_num, int w_den, int h_num, int h_den,
  140. + int pitch, int pixel_pitch,
  141. + int full_upload, const uint8_t *pixels,
  142. + int tex_target, int tex_format, int tex_type)
  143. +{
  144. + int width = in_width * w_num / w_den;
  145. + int full_width = in_full_width * w_num / w_den;
  146. + int height = in_height * h_num / h_den;
  147. + int full_height = in_full_height * h_num / h_den;
  148. + // This unpack alignment is the default, but setting it just in case.
  149. + glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
  150. +
  151. + int dst_width = full_upload ? full_width : width;
  152. + int dst_pitch = ALIGN(dst_width * pixel_pitch, 4);
  153. + if ( pitch != dst_pitch )
  154. + {
  155. + int buf_size = dst_pitch * full_height * pixel_pitch;
  156. + const uint8_t *source = pixels;
  157. + uint8_t *destination;
  158. + if( !sys->texture_temp_buf || sys->texture_temp_buf_size < buf_size )
  159. + {
  160. + free( sys->texture_temp_buf );
  161. + sys->texture_temp_buf = xmalloc( buf_size );
  162. + sys->texture_temp_buf_size = buf_size;
  163. + }
  164. + destination = sys->texture_temp_buf;
  165. +
  166. + for( int h = 0; h < height ; h++ )
  167. + {
  168. + memcpy( destination, source, width * pixel_pitch );
  169. + source += pitch;
  170. + destination += dst_pitch;
  171. + }
  172. + if (full_upload)
  173. + glTexImage2D( tex_target, 0, tex_format,
  174. + full_width, full_height,
  175. + 0, tex_format, tex_type, sys->texture_temp_buf );
  176. + else
  177. + glTexSubImage2D( tex_target, 0,
  178. + 0, 0,
  179. + width, height,
  180. + tex_format, tex_type, sys->texture_temp_buf );
  181. + } else {
  182. + if (full_upload)
  183. + glTexImage2D(tex_target, 0, tex_format,
  184. + full_width, full_height,
  185. + 0, tex_format, tex_type, pixels);
  186. + else
  187. + glTexSubImage2D(tex_target, 0,
  188. + 0, 0,
  189. + width, height,
  190. + tex_format, tex_type, pixels);
  191. + }
  192. +}
  193. +
  194. +static void ZeroCopyPrepare(vout_display_t *vd, picture_t *pic, subpicture_t *subpicture)
  195. {
  196. vout_display_sys_t *sys = vd->sys;
  197. if (likely([sys->glESView isAppActive]))
  198. [sys->glESView resetBuffers];
  199. +
  200. + // Subpictures
  201. + int last_count = sys->region_count;
  202. + gl_region_t *last = sys->region;
  203. +
  204. + sys->region_count = 0;
  205. + sys->region = NULL;
  206. +
  207. + if (subpicture)
  208. + {
  209. + int count = 0;
  210. + for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next)
  211. + count++;
  212. +
  213. + sys->region_count = count;
  214. + sys->region = calloc(count, sizeof(*sys->region));
  215. +
  216. + glActiveTexture(GL_TEXTURE0 + 0);
  217. +
  218. + int i = 0;
  219. + for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next, i++) {
  220. + gl_region_t *glr = &sys->region[i];
  221. +
  222. + glr->format = GL_RGBA;
  223. + glr->type = GL_UNSIGNED_BYTE;
  224. + glr->width = r->fmt.i_visible_width;
  225. + glr->height = r->fmt.i_visible_height;
  226. +
  227. + glr->width = GetAlignedSize(glr->width);
  228. + //glr->height = GetAlignedSize(glr->height);
  229. +
  230. + glr->tex_width = (float) r->fmt.i_visible_width / glr->width;
  231. + glr->tex_height = (float) r->fmt.i_visible_height / glr->height;
  232. +
  233. + glr->alpha = (float)subpicture->i_alpha * r->i_alpha / 255 / 255;
  234. + glr->left = 2.0 * (r->i_x ) / subpicture->i_original_picture_width - 1.0;
  235. + glr->top = -2.0 * (r->i_y ) / subpicture->i_original_picture_height + 1.0;
  236. + glr->right = 2.0 * (r->i_x + r->fmt.i_visible_width ) / subpicture->i_original_picture_width - 1.0;
  237. + glr->bottom = -2.0 * (r->i_y + r->fmt.i_visible_height) / subpicture->i_original_picture_height + 1.0;
  238. +
  239. + glr->texture = 0;
  240. + /* Try to recycle the textures allocated by the previous
  241. + call to this function. */
  242. + for (int j = 0; j < last_count; j++) {
  243. + if (last[j].texture &&
  244. + last[j].width == glr->width &&
  245. + last[j].height == glr->height &&
  246. + last[j].format == glr->format &&
  247. + last[j].type == glr->type) {
  248. + glr->texture = last[j].texture;
  249. + memset(&last[j], 0, sizeof(last[j]));
  250. + break;
  251. + }
  252. + }
  253. +
  254. + const int pixels_offset = r->fmt.i_y_offset * r->p_picture->p->i_pitch +
  255. + r->fmt.i_x_offset * r->p_picture->p->i_pixel_pitch;
  256. + if (glr->texture) {
  257. + /* A texture was successfully recycled, reuse it. */
  258. + glBindTexture(GL_TEXTURE_2D, glr->texture);
  259. + Upload(sys, r->fmt.i_visible_width, r->fmt.i_visible_height, glr->width, glr->height, 1, 1, 1, 1,
  260. + r->p_picture->p->i_pitch, r->p_picture->p->i_pixel_pitch, 0,
  261. + &r->p_picture->p->p_pixels[pixels_offset], GL_TEXTURE_2D, glr->format, glr->type);
  262. + } else {
  263. + /* Could not recycle a previous texture, generate a new one. */
  264. + glGenTextures(1, &glr->texture);
  265. + glBindTexture(GL_TEXTURE_2D, glr->texture);
  266. +
  267. + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  268. + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  269. + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  270. + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  271. + Upload(sys, r->fmt.i_visible_width, r->fmt.i_visible_height, glr->width, glr->height, 1, 1, 1, 1,
  272. + r->p_picture->p->i_pitch, r->p_picture->p->i_pixel_pitch, 1,
  273. + &r->p_picture->p->p_pixels[pixels_offset], GL_TEXTURE_2D, glr->format, glr->type);
  274. + }
  275. + }
  276. + }
  277. +
  278. + for (int i = 0; i < last_count; i++) {
  279. + if (last[i].texture)
  280. + glDeleteTextures(1, &last[i].texture);
  281. + }
  282. + free(last);
  283. }
  284. static void ZeroCopyDisplay(vout_display_t *vd, picture_t *pic, subpicture_t *subpicture)
  285. @@ -961,6 +1162,8 @@ static void ZeroCopyDisplay(vout_display_t *vd, picture_t *pic, subpicture_t *su
  286. glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  287. + [self drawSubpictures];
  288. +
  289. glBindRenderbuffer(GL_RENDERBUFFER, _renderBuffer);
  290. [_eaglContext presentRenderbuffer:GL_RENDERBUFFER];
  291. @@ -971,6 +1174,54 @@ done:
  292. [EAGLContext setCurrentContext:previousContext];
  293. }
  294. +- (void)drawSubpictures
  295. +{
  296. + vout_display_sys_t *sys = _voutDisplay->sys;
  297. +
  298. + /* Draw the subpictures */
  299. +
  300. + glUseProgram(self.shaderProgramSubpictures);
  301. +
  302. + GLfloat transformMatrix[16];
  303. + orientationTransformMatrix(transformMatrix, _voutDisplay->fmt.orientation);
  304. + glUniformMatrix4fv(glGetUniformLocation(self.shaderProgramSubpictures, "transformMatrix"), 1, GL_FALSE, transformMatrix);
  305. +
  306. + glUniform1i(glGetUniformLocation(self.shaderProgramSubpictures, "Texture"), 0);
  307. +
  308. + glEnable(GL_BLEND);
  309. + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  310. +
  311. + glActiveTexture(GL_TEXTURE0 + 0);
  312. + for (int i = 0; i < sys->region_count; i++) {
  313. + gl_region_t *glr = &sys->region[i];
  314. + const GLfloat vertexCoord[] = {
  315. + glr->left, glr->top,
  316. + glr->left, glr->bottom,
  317. + glr->right, glr->top,
  318. + glr->right, glr->bottom,
  319. + };
  320. + const GLfloat textureCoord[] = {
  321. + 0.0, 0.0,
  322. + 0.0, glr->tex_height,
  323. + glr->tex_width, 0.0,
  324. + glr->tex_width, glr->tex_height,
  325. + };
  326. +
  327. + glBindTexture(GL_TEXTURE_2D, glr->texture);
  328. + glUniform4f(glGetUniformLocation(self.shaderProgramSubpictures, "FillColor"), 1.0f, 1.0f, 1.0f, glr->alpha);
  329. +
  330. + glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, vertexCoord);
  331. + glEnableVertexAttribArray(ATTRIB_VERTEX);
  332. +
  333. + glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, 0, 0, textureCoord);
  334. + glEnableVertexAttribArray(ATTRIB_TEXCOORD);
  335. +
  336. + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  337. + }
  338. + glDisable(GL_BLEND);
  339. +}
  340. +
  341. +
  342. - (void)setupZeroCopyGL
  343. {
  344. EAGLContext *previousContext = [EAGLContext currentContext];
  345. @@ -1017,55 +1268,59 @@ done:
  346. - (BOOL)loadShaders
  347. {
  348. - GLuint vertShader, fragShader;
  349. - NSURL *vertShaderURL, *fragShaderURL;
  350. + GLuint vertShader = 0;
  351. + GLuint fragShader = 0;
  352. + GLuint fragShaderSub = 0;
  353. // Create the shader program.
  354. self.shaderProgram = glCreateProgram();
  355. + self.shaderProgramSubpictures = glCreateProgram();
  356. // Create and compile the vertex shader.
  357. if (![self compileShader:&vertShader type:GL_VERTEX_SHADER sourceString:vertexShaderString]) {
  358. if (_voutDisplay)
  359. msg_Err(_voutDisplay, "Failed to compile vertex shader");
  360. - return NO;
  361. + goto error;
  362. }
  363. // Create and compile fragment shader.
  364. if (![self compileShader:&fragShader type:GL_FRAGMENT_SHADER sourceString:fragmentShaderString]) {
  365. if (_voutDisplay)
  366. msg_Err(_voutDisplay, "Failed to compile fragment shader");
  367. - return NO;
  368. + goto error;
  369. + }
  370. +
  371. + if (![self compileShader:&fragShaderSub type:GL_FRAGMENT_SHADER sourceString:fragmentShaderRGBAString]) {
  372. + if (_voutDisplay)
  373. + msg_Err(_voutDisplay, "Failed to compile the RGBA fragment shader");
  374. + goto error;
  375. }
  376. // Attach vertex shader to program.
  377. glAttachShader(self.shaderProgram, vertShader);
  378. + glAttachShader(self.shaderProgramSubpictures, vertShader);
  379. // Attach fragment shader to program.
  380. glAttachShader(self.shaderProgram, fragShader);
  381. + glAttachShader(self.shaderProgramSubpictures, fragShaderSub);
  382. // Bind attribute locations. This needs to be done prior to linking.
  383. glBindAttribLocation(self.shaderProgram, ATTRIB_VERTEX, "position");
  384. glBindAttribLocation(self.shaderProgram, ATTRIB_TEXCOORD, "texCoord");
  385. + glBindAttribLocation(self.shaderProgramSubpictures, ATTRIB_VERTEX, "position");
  386. + glBindAttribLocation(self.shaderProgramSubpictures, ATTRIB_TEXCOORD, "texCoord");
  387. // Link the program.
  388. if (![self linkProgram:self.shaderProgram]) {
  389. if (_voutDisplay)
  390. - msg_Err(_voutDisplay, "Failed to link program: %d", self.shaderProgram);
  391. -
  392. - if (vertShader) {
  393. - glDeleteShader(vertShader);
  394. - vertShader = 0;
  395. - }
  396. - if (fragShader) {
  397. - glDeleteShader(fragShader);
  398. - fragShader = 0;
  399. - }
  400. - if (self.shaderProgram) {
  401. - glDeleteProgram(self.shaderProgram);
  402. - self.shaderProgram = 0;
  403. - }
  404. + msg_Err(_voutDisplay, "Failed to link program for main pictures: %d", self.shaderProgram);
  405. + goto error;
  406. + }
  407. - return NO;
  408. + if (![self linkProgram:self.shaderProgramSubpictures]) {
  409. + if (_voutDisplay)
  410. + msg_Err(_voutDisplay, "Failed to link program for subpictures: %d", self.shaderProgramSubpictures);
  411. + goto error;
  412. }
  413. // Get uniform locations.
  414. @@ -1075,16 +1330,35 @@ done:
  415. uniforms[UNIFORM_TRANSFORM_MATRIX] = glGetUniformLocation(self.shaderProgram, "transformMatrix");
  416. // Release vertex and fragment shaders.
  417. - if (vertShader) {
  418. - glDetachShader(self.shaderProgram, vertShader);
  419. + glDetachShader(self.shaderProgram, vertShader);
  420. + glDetachShader(self.shaderProgramSubpictures, vertShader);
  421. + glDeleteShader(vertShader);
  422. +
  423. + glDetachShader(self.shaderProgram, fragShader);
  424. + glDeleteShader(fragShader);
  425. +
  426. + glDetachShader(self.shaderProgramSubpictures, fragShaderSub);
  427. + glDeleteShader(fragShaderSub);
  428. +
  429. + return YES;
  430. +
  431. +error:
  432. + if (vertShader)
  433. glDeleteShader(vertShader);
  434. - }
  435. - if (fragShader) {
  436. - glDetachShader(self.shaderProgram, fragShader);
  437. +
  438. + if (fragShader)
  439. glDeleteShader(fragShader);
  440. - }
  441. - return YES;
  442. + if (fragShaderSub)
  443. + glDeleteShader(fragShaderSub);
  444. +
  445. + if (self.shaderProgram)
  446. + glDeleteProgram(self.shaderProgram);
  447. +
  448. + if (self.shaderProgramSubpictures)
  449. + glDeleteProgram(self.shaderProgramSubpictures);
  450. +
  451. + return NO;
  452. }
  453. - (BOOL)compileShader:(GLuint *)shader type:(GLenum)type sourceString:sourceString
  454. @@ -1097,7 +1371,6 @@ done:
  455. glShaderSource(*shader, 1, &source, NULL);
  456. glCompileShader(*shader);
  457. -#ifndef NDEBUG
  458. GLint logLength;
  459. glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &logLength);
  460. if (logLength > 0) {
  461. @@ -1107,7 +1380,6 @@ done:
  462. msg_Dbg(_voutDisplay, "Shader compile log:\n%s", log);
  463. free(log);
  464. }
  465. -#endif
  466. glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);
  467. if (status == 0) {
  468. @@ -1123,7 +1395,6 @@ done:
  469. GLint status;
  470. glLinkProgram(prog);
  471. -#ifndef NDEBUG
  472. GLint logLength;
  473. glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength);
  474. if (logLength > 0) {
  475. @@ -1133,7 +1404,6 @@ done:
  476. msg_Dbg(_voutDisplay, "Program link log:\n%s", log);
  477. free(log);
  478. }
  479. -#endif
  480. glGetProgramiv(prog, GL_LINK_STATUS, &status);
  481. if (status == 0) {
  482. --
  483. 2.9.3