QGHWDMP4OpenGLView.m 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  1. // QGHWDMP4OpenGLView.m
  2. // Tencent is pleased to support the open source community by making vap available.
  3. //
  4. // Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
  5. //
  6. // Licensed under the MIT License (the "License"); you may not use this file except in
  7. // compliance with the License. You may obtain a copy of the License at
  8. //
  9. // http://opensource.org/licenses/MIT
  10. //
  11. // Unless required by applicable law or agreed to in writing, software distributed under the License is
  12. // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
  13. // either express or implied. See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. #import "QGHWDMP4OpenGLView.h"
  16. #import <QuartzCore/QuartzCore.h>
  17. #import <AVFoundation/AVUtilities.h>
  18. #import <mach/mach_time.h>
  19. #import <GLKit/GLKit.h>
  20. #import "VAPMacros.h"
  21. // Uniform index.
  22. enum {
  23. HWD_UNIFORM_Y,
  24. HWD_UNIFORM_UV,
  25. HWD_UNIFORM_COLOR_CONVERSION_MATRIX,
  26. HWD_NUM_UNIFORMS
  27. };
  28. GLint hwd_uniforms[HWD_NUM_UNIFORMS];
  29. // Attribute index.
  30. enum {
  31. ATTRIB_VERTEX,
  32. ATTRIB_TEXCOORD_RGB,
  33. ATTRIB_TEXCOORD_ALPHA,
  34. NUM_ATTRIBUTES
  35. };
  36. // BT.709-HDTV.
  37. static const GLfloat kQGColorConversion709[] = {
  38. 1.164, 1.164, 1.164,
  39. 0.0, -0.213, 2.112,
  40. 1.793, -0.533, 0.0,
  41. };
  42. // BT.601 full range-http://www.equasys.de/colorconversion.html
  43. const GLfloat kQGColorConversion601FullRange[] = {
  44. 1.0, 1.0, 1.0,
  45. 0.0, -0.343, 1.765,
  46. 1.4, -0.711, 0.0,
  47. };
  48. // texture coords for blend
  49. const GLfloat textureCoordLeft[] = { // 左侧
  50. 0.5, 0.0,
  51. 0.0, 0.0,
  52. 0.5, 1.0,
  53. 0.0, 1.0
  54. };
  55. const GLfloat textureCoordRight[] = { // 右侧
  56. 1.0, 0.0,
  57. 0.5, 0.0,
  58. 1.0, 1.0,
  59. 0.5, 1.0
  60. };
  61. const GLfloat textureCoordTop[] = { // 上侧
  62. 1.0, 0.0,
  63. 0.0, 0.0,
  64. 1.0, 0.5,
  65. 0.0, 0.5
  66. };
  67. const GLfloat textureCoordBottom[] = { // 下侧
  68. 1.0, 0.5,
  69. 0.0, 0.5,
  70. 1.0, 1.0,
  71. 0.0, 1.0
  72. };
  73. #undef cos
  74. #undef sin
  75. NSString *const kVertexShaderSource = SHADER_STRING
  76. (
  77. attribute vec4 position;
  78. attribute vec2 RGBTexCoord;
  79. attribute vec2 alphaTexCoord;
  80. varying vec2 RGBTexCoordVarying;
  81. varying vec2 alphaTexCoordVarying;
  82. void main()
  83. {
  84. float preferredRotation = 3.14;
  85. mat4 rotationMatrix = mat4(cos(preferredRotation), -sin(preferredRotation), 0.0, 0.0,sin(preferredRotation),cos(preferredRotation), 0.0, 0.0,0.0,0.0,1.0,0.0,0.0,0.0, 0.0,1.0);
  86. gl_Position = rotationMatrix * position;
  87. RGBTexCoordVarying = RGBTexCoord;
  88. alphaTexCoordVarying = alphaTexCoord;
  89. }
  90. );
  91. NSString *const kFragmentShaderSource = SHADER_STRING
  92. (
  93. varying highp vec2 RGBTexCoordVarying;
  94. varying highp vec2 alphaTexCoordVarying;
  95. precision mediump float;
  96. uniform sampler2D SamplerY;
  97. uniform sampler2D SamplerUV;
  98. uniform mat3 colorConversionMatrix;
  99. void main()
  100. {
  101. mediump vec3 yuv_rgb;
  102. lowp vec3 rgb_rgb;
  103. mediump vec3 yuv_alpha;
  104. lowp vec3 rgb_alpha;
  105. // Subtract constants to map the video range start at 0
  106. yuv_rgb.x = (texture2D(SamplerY, RGBTexCoordVarying).r);// - (16.0/255.0));
  107. yuv_rgb.yz = (texture2D(SamplerUV, RGBTexCoordVarying).ra - vec2(0.5, 0.5));
  108. rgb_rgb = colorConversionMatrix * yuv_rgb;
  109. yuv_alpha.x = (texture2D(SamplerY, alphaTexCoordVarying).r);// - (16.0/255.0));
  110. yuv_alpha.yz = (texture2D(SamplerUV, alphaTexCoordVarying).ra - vec2(0.5, 0.5));
  111. rgb_alpha = colorConversionMatrix * yuv_alpha;
  112. gl_FragColor = vec4(rgb_rgb,rgb_alpha.r);
  113. // gl_FragColor = vec4(1, 0, 0, 1);
  114. }
  115. );
  116. @interface QGHWDMP4OpenGLView() {
  117. GLint _backingWidth;
  118. GLint _backingHeight;
  119. CVOpenGLESTextureRef _lumaTexture;
  120. CVOpenGLESTextureRef _chromaTexture;
  121. CVOpenGLESTextureCacheRef _textureCache;
  122. GLuint _frameBufferHandle;
  123. GLuint _colorBufferHandle;
  124. const GLfloat *_preferredConversion;
  125. }
  126. @property GLuint program;
  127. - (void)setupBuffers;
  128. - (void)cleanupTextures;
  129. - (BOOL)isValidateProgram:(GLuint)prog;
  130. - (BOOL)loadShaders;
  131. - (BOOL)compileShader:(GLuint *)shader type:(GLenum)type URL:(NSURL *)URL;
  132. - (BOOL)linkProgram:(GLuint)prog;
  133. @end
  134. @implementation QGHWDMP4OpenGLView
  135. + (Class)layerClass {
  136. return [CAEAGLLayer class];
  137. }
  138. - (id)initWithCoder:(NSCoder *)aDecoder {
  139. if ((self = [super initWithCoder:aDecoder])) {
  140. if (![self commonInit]) {
  141. return nil;
  142. }
  143. }
  144. return self;
  145. }
  146. - (instancetype)init {
  147. if (self = [super init]) {
  148. if (![self commonInit]) {
  149. return nil;
  150. }
  151. }
  152. return self;
  153. }
  154. - (instancetype)initWithFrame:(CGRect)frame {
  155. if (self = [super initWithFrame:frame]) {
  156. if (![self commonInit]) {
  157. return nil;
  158. }
  159. }
  160. return self;
  161. }
  162. - (BOOL)commonInit {
  163. self.contentScaleFactor = [[UIScreen mainScreen] scale];
  164. CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
  165. eaglLayer.opaque = NO;
  166. eaglLayer.drawableProperties = @{ kEAGLDrawablePropertyRetainedBacking :[NSNumber numberWithBool:NO],
  167. kEAGLDrawablePropertyColorFormat : kEAGLColorFormatRGBA8};
  168. _glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
  169. if (!_glContext || ![EAGLContext setCurrentContext:_glContext] || ![self loadShaders]) {
  170. return NO;
  171. }
  172. _preferredConversion = kQGColorConversion709;
  173. return YES;
  174. }
  175. - (void)dealloc {
  176. [self cleanupTextures];
  177. if(_textureCache) {
  178. CFRelease(_textureCache);
  179. }
  180. if ([self.displayDelegate respondsToSelector:@selector(onViewUnavailableStatus)]) {
  181. [self.displayDelegate onViewUnavailableStatus];
  182. }
  183. }
  184. # pragma mark - OpenGL setup
  185. /**
  186. 初始化opengl环境
  187. */
  188. - (void)setupGL {
  189. VAP_Info(kQGVAPModuleCommon, @"setupGL");
  190. [EAGLContext setCurrentContext:_glContext];
  191. [self setupBuffers];
  192. [self loadShaders];
  193. glUseProgram(self.program);
  194. glUniform1i(hwd_uniforms[HWD_UNIFORM_Y], 0);
  195. glUniform1i(hwd_uniforms[HWD_UNIFORM_UV], 1);
  196. glUniformMatrix3fv(hwd_uniforms[HWD_UNIFORM_COLOR_CONVERSION_MATRIX], 1, GL_FALSE, _preferredConversion);
  197. // Create CVOpenGLESTextureCacheRef for optimal CVPixelBufferRef to GLES texture conversion.
  198. if (!_textureCache) {
  199. CVReturn err = CVOpenGLESTextureCacheCreate(kCFAllocatorDefault, NULL, _glContext, NULL, &_textureCache);
  200. if (err != noErr) {
  201. VAP_Event(kQGVAPModuleCommon, @"Error at CVOpenGLESTextureCacheCreate %d", err);
  202. return;
  203. }
  204. }
  205. glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
  206. }
  207. #pragma mark - Utilities
  208. - (void)setupBuffers {
  209. glDisable(GL_DEPTH_TEST);
  210. glEnableVertexAttribArray(ATTRIB_VERTEX);
  211. glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), 0);
  212. glEnableVertexAttribArray(ATTRIB_TEXCOORD_RGB);
  213. glVertexAttribPointer(ATTRIB_TEXCOORD_RGB, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), 0);
  214. glEnableVertexAttribArray(ATTRIB_TEXCOORD_ALPHA);
  215. glVertexAttribPointer(ATTRIB_TEXCOORD_ALPHA, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), 0);
  216. glGenFramebuffers(1, &_frameBufferHandle);
  217. glBindFramebuffer(GL_FRAMEBUFFER, _frameBufferHandle);
  218. glGenRenderbuffers(1, &_colorBufferHandle);
  219. glBindRenderbuffer(GL_RENDERBUFFER, _colorBufferHandle);
  220. [_glContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer *)self.layer];
  221. glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &_backingWidth);
  222. glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_backingHeight);
  223. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _colorBufferHandle);
  224. if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
  225. VAP_Event(kQGVAPModuleCommon, @"Failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER));
  226. }
  227. }
  228. - (void)layoutSubviews {
  229. [super layoutSubviews];
  230. [self updateBackingSize];
  231. }
  232. /**
  233. 根据容器大小更新渲染尺寸
  234. */
  235. - (void)updateBackingSize {
  236. if ([EAGLContext currentContext] != _glContext) {
  237. [EAGLContext setCurrentContext:_glContext];
  238. }
  239. [_glContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer *)self.layer];
  240. glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &_backingWidth);
  241. glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_backingHeight);
  242. }
  243. - (void)cleanupTextures {
  244. if (_lumaTexture) {
  245. CFRelease(_lumaTexture);
  246. _lumaTexture = NULL;
  247. }
  248. if (_chromaTexture) {
  249. CFRelease(_chromaTexture);
  250. _chromaTexture = NULL;
  251. }
  252. CVOpenGLESTextureCacheFlush(_textureCache, 0);
  253. }
  254. #pragma mark - OpenGLES drawing
  255. /**
  256. 上屏
  257. @param pixelBuffer 硬解出来的samplebuffer数据
  258. */
  259. - (void)displayPixelBuffer:(CVPixelBufferRef)pixelBuffer {
  260. if (!self.window && [self.displayDelegate respondsToSelector:@selector(onViewUnavailableStatus)]) {
  261. [self.displayDelegate onViewUnavailableStatus];
  262. return ;
  263. }
  264. if ([EAGLContext currentContext] != _glContext) {
  265. [EAGLContext setCurrentContext:_glContext];
  266. }
  267. CVReturn err;
  268. if (pixelBuffer != NULL) {
  269. int frameWidth = (int)CVPixelBufferGetWidth(pixelBuffer);
  270. int frameHeight = (int)CVPixelBufferGetHeight(pixelBuffer);
  271. if (!_textureCache) {
  272. VAP_Event(kQGVAPModuleCommon, @"No video texture cache");
  273. return;
  274. }
  275. [self cleanupTextures];
  276. _preferredConversion = kQGColorConversion601FullRange;
  277. //y
  278. glActiveTexture(GL_TEXTURE0);
  279. err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
  280. _textureCache,
  281. pixelBuffer,
  282. NULL,
  283. GL_TEXTURE_2D,
  284. GL_LUMINANCE,
  285. frameWidth,
  286. frameHeight,
  287. GL_LUMINANCE,
  288. GL_UNSIGNED_BYTE,
  289. 0,
  290. &_lumaTexture);
  291. if (err) {
  292. VAP_Event(kQGVAPModuleCommon, @"Error at CVOpenGLESTextureCacheCreateTextureFromImage %d", err);
  293. }
  294. glBindTexture(CVOpenGLESTextureGetTarget(_lumaTexture), CVOpenGLESTextureGetName(_lumaTexture));
  295. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  296. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  297. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  298. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  299. // uv
  300. glActiveTexture(GL_TEXTURE1);
  301. err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
  302. _textureCache,
  303. pixelBuffer,
  304. NULL,
  305. GL_TEXTURE_2D,
  306. GL_LUMINANCE_ALPHA,
  307. frameWidth / 2.0,
  308. frameHeight / 2.0,
  309. GL_LUMINANCE_ALPHA,
  310. GL_UNSIGNED_BYTE,
  311. 1,
  312. &_chromaTexture);
  313. if (err) {
  314. VAP_Error(kQGVAPModuleCommon, @"Error at CVOpenGLESTextureCacheCreateTextureFromImage %d", err);
  315. }
  316. glBindTexture(CVOpenGLESTextureGetTarget(_chromaTexture), CVOpenGLESTextureGetName(_chromaTexture));
  317. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  318. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  319. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  320. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  321. glBindFramebuffer(GL_FRAMEBUFFER, _frameBufferHandle);
  322. // Set the view port to the entire view.
  323. glViewport(0, 0, _backingWidth, _backingHeight);
  324. }
  325. // glClearColor(0.1f, 0.0f, 0.0f, 1.0f);
  326. glClear(GL_COLOR_BUFFER_BIT);
  327. glUseProgram(self.program);
  328. glUniformMatrix3fv(hwd_uniforms[HWD_UNIFORM_COLOR_CONVERSION_MATRIX], 1, GL_FALSE, _preferredConversion);
  329. // 根据视频的方向和高宽比设置四个顶点。
  330. CGRect vertexRect = AVMakeRectWithAspectRatioInsideRect(CGSizeMake(_backingWidth, _backingHeight), self.layer.bounds);
  331. // 计算归一化四坐标来绘制坐标系。
  332. CGSize normalizedSamplingSize = CGSizeMake(0.0, 0.0);
  333. CGSize cropScaleAmount = CGSizeMake(vertexRect.size.width/self.layer.bounds.size.width, vertexRect.size.height/self.layer.bounds.size.height);
  334. if (cropScaleAmount.width > cropScaleAmount.height) {
  335. normalizedSamplingSize.width = 1.0;
  336. normalizedSamplingSize.height = cropScaleAmount.height/cropScaleAmount.width;
  337. } else {
  338. normalizedSamplingSize.width = 1.0;
  339. normalizedSamplingSize.height = cropScaleAmount.width/cropScaleAmount.height;
  340. }
  341. GLfloat quadVertexData [] = {
  342. -1 * normalizedSamplingSize.width, -1 * normalizedSamplingSize.height,
  343. normalizedSamplingSize.width, -1 * normalizedSamplingSize.height,
  344. -1 * normalizedSamplingSize.width, normalizedSamplingSize.height,
  345. normalizedSamplingSize.width, normalizedSamplingSize.height,
  346. };
  347. // 更新顶点数据
  348. glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, quadVertexData);
  349. glEnableVertexAttribArray(ATTRIB_VERTEX);
  350. glVertexAttribPointer(ATTRIB_TEXCOORD_RGB, 2, GL_FLOAT, 0, 0, [self quadTextureRGBData]);
  351. glEnableVertexAttribArray(ATTRIB_TEXCOORD_RGB);
  352. glVertexAttribPointer(ATTRIB_TEXCOORD_ALPHA, 2, GL_FLOAT, 0, 0, [self quedTextureAlphaData]);
  353. glEnableVertexAttribArray(ATTRIB_TEXCOORD_ALPHA);
  354. glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  355. glBindRenderbuffer(GL_RENDERBUFFER, _colorBufferHandle);
  356. if ([EAGLContext currentContext] == _glContext && !self.pause && self.window && [UIApplication sharedApplication].applicationState != UIApplicationStateBackground) {
  357. [_glContext presentRenderbuffer:GL_RENDERBUFFER];
  358. }
  359. }
  360. - (const void *)quedTextureAlphaData {
  361. switch (self.blendMode) {
  362. case QGHWDTextureBlendMode_AlphaLeft:
  363. return textureCoordLeft;
  364. case QGHWDTextureBlendMode_AlphaRight:
  365. return textureCoordRight;
  366. case QGHWDTextureBlendMode_AlphaTop:
  367. return textureCoordTop;
  368. case QGHWDTextureBlendMode_AlphaBottom:
  369. return textureCoordBottom;
  370. default:
  371. return textureCoordLeft;
  372. }
  373. }
  374. - (const void *)quadTextureRGBData {
  375. switch (self.blendMode) {
  376. case QGHWDTextureBlendMode_AlphaLeft:
  377. return textureCoordRight;
  378. case QGHWDTextureBlendMode_AlphaRight:
  379. return textureCoordLeft;
  380. case QGHWDTextureBlendMode_AlphaTop:
  381. return textureCoordBottom;
  382. case QGHWDTextureBlendMode_AlphaBottom:
  383. return textureCoordTop;
  384. default:
  385. return textureCoordRight;
  386. }
  387. }
  388. #pragma mark - OpenGL ES 2 shader compilation
  389. - (BOOL)loadShaders {
  390. GLuint vShader, fShader;
  391. self.program = glCreateProgram();
  392. // Create and compile the vertex shader.
  393. if (![self compileShader:&vShader type:GL_VERTEX_SHADER source:kVertexShaderSource]) {
  394. VAP_Error(kQGVAPModuleCommon, @"Failed to compile vertex shader");
  395. return NO;
  396. }
  397. // Create and compile fragment shader.
  398. if (![self compileShader:&fShader type:GL_FRAGMENT_SHADER source:kFragmentShaderSource]) {
  399. VAP_Error(kQGVAPModuleCommon, @"Failed to compile fragment shader");
  400. return NO;
  401. }
  402. // Attach vertex shader to program.
  403. glAttachShader(self.program, vShader);
  404. // Attach fragment shader to program.
  405. glAttachShader(self.program, fShader);
  406. // Bind attribute locations. This needs to be done prior to linking.
  407. glBindAttribLocation(self.program, ATTRIB_VERTEX, "position");
  408. glBindAttribLocation(self.program, ATTRIB_TEXCOORD_RGB, "RGBTexCoord");
  409. glBindAttribLocation(self.program, ATTRIB_TEXCOORD_ALPHA, "alphaTexCoord");
  410. // Link the program.
  411. if (![self linkProgram:self.program]) {
  412. VAP_Event(kQGVAPModuleCommon, @"Failed to link program: %d", self.program);
  413. if (vShader) {
  414. glDeleteShader(vShader);
  415. vShader = 0;
  416. }
  417. if (fShader) {
  418. glDeleteShader(fShader);
  419. fShader = 0;
  420. }
  421. if (self.program) {
  422. glDeleteProgram(self.program);
  423. self.program = 0;
  424. }
  425. return NO;
  426. }
  427. // Get uniforms' location.
  428. hwd_uniforms[HWD_UNIFORM_Y] = glGetUniformLocation(self.program, "SamplerY");
  429. hwd_uniforms[HWD_UNIFORM_UV] = glGetUniformLocation(self.program, "SamplerUV");
  430. hwd_uniforms[HWD_UNIFORM_COLOR_CONVERSION_MATRIX] = glGetUniformLocation(self.program, "colorConversionMatrix");
  431. // Release vertex and fragment shaders.
  432. if (vShader) {
  433. glDetachShader(self.program, vShader);
  434. glDeleteShader(vShader);
  435. }
  436. if (fShader) {
  437. glDetachShader(self.program, fShader);
  438. glDeleteShader(fShader);
  439. }
  440. return YES;
  441. }
  442. - (BOOL)compileShader:(GLuint *)shader type:(GLenum)type source:(const NSString *)sourceString {
  443. GLint status;
  444. const GLchar *source;
  445. source = (GLchar *)[sourceString UTF8String];
  446. *shader = glCreateShader(type);
  447. glShaderSource(*shader, 1, &source, NULL);
  448. glCompileShader(*shader);
  449. #if defined(DEBUG)
  450. GLint lengthOfLog;
  451. glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &lengthOfLog);
  452. if (lengthOfLog > 0) {
  453. GLchar *log = (GLchar *)malloc(lengthOfLog);
  454. glGetShaderInfoLog(*shader, lengthOfLog, &lengthOfLog, log);
  455. VAP_Info(kQGVAPModuleCommon, @"MODULE_DECODE Shader compile log:\n%s", log)
  456. free(log);
  457. }
  458. #endif
  459. glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);
  460. if (status == 0) {
  461. glDeleteShader(*shader);
  462. return NO;
  463. }
  464. return YES;
  465. }
  466. - (BOOL)compileShader:(GLuint *)shader type:(GLenum)type URL:(NSURL *)URL {
  467. VAP_Info(kQGVAPModuleCommon, @"compileShader");
  468. NSError *error;
  469. NSString *sourceString = [[NSString alloc] initWithContentsOfURL:URL encoding:NSUTF8StringEncoding error:&error];
  470. if (sourceString == nil) {
  471. VAP_Event(kQGVAPModuleCommon, @"Failed to load vertex shader: %@", [error localizedDescription]);
  472. return NO;
  473. }
  474. const GLchar *source;
  475. source = (GLchar *)[sourceString UTF8String];
  476. *shader = glCreateShader(type);
  477. glShaderSource(*shader, 1, &source, NULL);
  478. glCompileShader(*shader);
  479. #if defined(DEBUG)
  480. GLint lengthOfLog;
  481. glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &lengthOfLog);
  482. if (lengthOfLog > 0) {
  483. GLchar *log = (GLchar *)malloc(lengthOfLog);
  484. glGetShaderInfoLog(*shader, lengthOfLog, &lengthOfLog, log);
  485. VAP_Info(kQGVAPModuleCommon, @"Shader compile log:\n%s", log);
  486. free(log);
  487. }
  488. #endif
  489. GLint status;
  490. glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);
  491. if (status == 0) {
  492. glDeleteShader(*shader);
  493. return NO;
  494. }
  495. return YES;
  496. }
  497. - (BOOL)linkProgram:(GLuint)prog {
  498. GLint status;
  499. glLinkProgram(prog);
  500. #if defined(DEBUG)
  501. GLint lengthOfLog;
  502. glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &lengthOfLog);
  503. if (lengthOfLog > 0) {
  504. GLchar *log = (GLchar *)malloc(lengthOfLog);
  505. glGetProgramInfoLog(prog, lengthOfLog, &lengthOfLog, log);
  506. VAP_Info(kQGVAPModuleCommon, @"Program link log:\n%s", log);
  507. free(log);
  508. }
  509. #endif
  510. glGetProgramiv(prog, GL_LINK_STATUS, &status);
  511. if (status == 0) {
  512. return NO;
  513. }
  514. return YES;
  515. }
  516. - (BOOL)isValidateProgram:(GLuint)prog {
  517. GLint logLength, status;
  518. glValidateProgram(prog);
  519. glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength);
  520. if (logLength > 0) {
  521. GLchar *log = (GLchar *)malloc(logLength);
  522. glGetProgramInfoLog(prog, logLength, &logLength, log);
  523. VAP_Info(kQGVAPModuleCommon, @"Program validate log:\n%s", log);
  524. free(log);
  525. }
  526. glGetProgramiv(prog, GL_VALIDATE_STATUS, &status);
  527. if (status == 0) {
  528. VAP_Event(kQGVAPModuleCommon, @"program is not valid:%@",@(status));
  529. return NO;
  530. }
  531. VAP_Info(kQGVAPModuleCommon, @"programe is valid");
  532. return YES;
  533. }
  534. - (void)dispose {
  535. glDisableVertexAttribArray(ATTRIB_VERTEX);
  536. glDisableVertexAttribArray(ATTRIB_TEXCOORD_RGB);
  537. glDisableVertexAttribArray(ATTRIB_TEXCOORD_ALPHA);
  538. }
  539. @end