#include "wayland/window.h" #include namespace nv12 { const GLchar* fragmentSource = R"glsl( #version 320 es precision highp float; in vec2 Texcoord; uniform sampler2D textureY; uniform sampler2D textureUV; layout(location = 0) out vec4 fragColor; void main() { float r, g, b, y, u, v; vec2 coord = vec2(Texcoord.x, 1.0 - Texcoord.y); y = texture(textureY, coord).r - 0.0625; u = texture(textureUV, coord).r - 0.5; v = texture(textureUV, coord).g - 0.5; r = clamp(y + 1.370705 * v, 0.0, 1.0); g = clamp(y - 0.337633 * u - 0.698001 * v, 0.0, 1.0); b = clamp(y + 1.732446 * u, 0.0, 1.0); fragColor = vec4(r, g, b, 1.0); } )glsl"; class Shader { public: GLint texY; GLint texUV; GLuint innerTexture[2]{}; GLuint program; GLuint framebuffer{}; #if NV12_DEPTH_RENDERBUFFER GLuint depth_renderbuffer; #endif GLuint textureId; GLsizei width, height; Shader(GLuint _program, GLuint _textureId, GLsizei _width, GLsizei _height) : program(_program), textureId(_textureId), width(_width), height(_height) { texY = glGetUniformLocation(program, "textureY"); texUV = glGetUniformLocation(program, "textureUV"); glUseProgram(program); glGenTextures(2, &innerTexture[0]); glBindTexture(GL_TEXTURE_2D, textureId); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_HINT, GL_TRUE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr); #if NV12_DEPTH_RENDERBUFFER glGenRenderbuffers(1, &depth_renderbuffer); glBindRenderbuffer(GL_RENDERBUFFER, depth_renderbuffer); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height); glBindRenderbuffer(GL_RENDERBUFFER, 0); #endif glGenFramebuffers(1, &framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0); #if NV12_DEPTH_RENDERBUFFER glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_renderbuffer); #endif GLenum DrawBuffers[] = {GL_COLOR_ATTACHMENT0}; glDrawBuffers(1, DrawBuffers); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { switch (glCheckFramebufferStatus(GL_FRAMEBUFFER)) { case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: spdlog::error( "failed to draw to framebuffer: " "the framebuffer attachment points are framebuffer incomplete"); break; case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: spdlog::error( "failed to draw to framebuffer: " "the framebuffer does not have at least one image " "attached to it"); break; case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: spdlog::error( "failed to draw to framebuffer: " "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS"); break; case GL_FRAMEBUFFER_UNSUPPORTED: default: spdlog::error( "failed to draw to framebuffer: target is the default " "framebuffer, but the default framebuffer does not exist"); break; } return; } glBindFramebuffer(GL_FRAMEBUFFER, 0); } /** * @brief Load pixels * @param[in] y_buf Pointer to image data for luminance signal * @param[in] uv_buf Pointer to image data for color difference signal * @param[in] y_p_s No use * @param[in] y_s Texture image width for luminance signal * @param[in] uv_p_s No use * @param[in] uv_s Texture image width for color difference signal * @return void * @relation * flutter */ void loadPixels(unsigned char* y_buf, unsigned char* uv_buf, GLsizei y_p_s, GLsizei y_s, GLsizei uv_p_s, GLsizei uv_s) { (void)y_p_s; (void)uv_p_s; glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, innerTexture[0]); glUniform1i(texY, 0); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, y_s, height, 0, GL_RED, GL_UNSIGNED_BYTE, y_buf); glGenerateMipmap(GL_TEXTURE_2D); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, innerTexture[1]); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glUniform1i(texUV, 1); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RG8, uv_s / 2, height / 2, 0, GL_RG, GL_UNSIGNED_BYTE, uv_buf); glGenerateMipmap(GL_TEXTURE_2D); } }; } // namespace nv12