bool CRendererVTB::UploadTexture(int index) { YUVBUFFER &buf = m_buffers[index]; YUVPLANE (&planes)[YuvImage::MAX_PLANES] = m_buffers[index].fields[0]; VTB::CVideoBufferVTB *vb = dynamic_cast<VTB::CVideoBufferVTB*>(buf.videoBuffer); if (!vb) { return false; } CVImageBufferRef cvBufferRef = vb->GetPB(); glEnable(m_textureTarget); // It is the fastest way to render a CVPixelBuffer backed // with an IOSurface as there is no CPU -> GPU upload. CGLContextObj cgl_ctx = (CGLContextObj)g_Windowing.GetCGLContextObj(); IOSurfaceRef surface = CVPixelBufferGetIOSurface(cvBufferRef); OSType format_type = IOSurfaceGetPixelFormat(surface); if (format_type != kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange) { return false; } GLsizei surfplanes = IOSurfaceGetPlaneCount(surface); if (surfplanes != 2) { return false; } GLsizei widthY = IOSurfaceGetWidthOfPlane(surface, 0); GLsizei widthUV = IOSurfaceGetWidthOfPlane(surface, 1); GLsizei heightY = IOSurfaceGetHeightOfPlane(surface, 0); GLsizei heightUV = IOSurfaceGetHeightOfPlane(surface, 1); glBindTexture(m_textureTarget, planes[0].id); CGLTexImageIOSurface2D(cgl_ctx, m_textureTarget, GL_LUMINANCE, widthY, heightY, GL_LUMINANCE, GL_UNSIGNED_BYTE, surface, 0); glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glBindTexture(m_textureTarget, planes[1].id); CGLTexImageIOSurface2D(cgl_ctx, m_textureTarget, GL_LUMINANCE_ALPHA, widthUV, heightUV, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, surface, 1); glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glBindTexture(m_textureTarget, 0); glDisable(m_textureTarget); CalculateTextureSourceRects(index, 3); return true; }
EGLSurface Display::createPBufferSurface(EGLConfig config, const EGLint *attribList, EGLClientBuffer clientBuffer) { EGLint width = -1, height = -1, ioSurfacePlane = -1; EGLenum textureFormat = EGL_NO_TEXTURE; EGLenum textureTarget = EGL_NO_TEXTURE; EGLenum clientBufferFormat = EGL_NO_TEXTURE; EGLenum clientBufferType = EGL_NO_TEXTURE; EGLBoolean largestPBuffer = EGL_FALSE; const Config *configuration = mConfigSet.get(config); if(attribList) { while(*attribList != EGL_NONE) { switch(attribList[0]) { case EGL_WIDTH: width = attribList[1]; break; case EGL_HEIGHT: height = attribList[1]; break; case EGL_LARGEST_PBUFFER: largestPBuffer = attribList[1]; break; case EGL_TEXTURE_FORMAT: switch(attribList[1]) { case EGL_NO_TEXTURE: case EGL_TEXTURE_RGB: case EGL_TEXTURE_RGBA: textureFormat = attribList[1]; break; default: return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); } break; case EGL_TEXTURE_INTERNAL_FORMAT_ANGLE: switch(attribList[1]) { case GL_RED: case GL_R16UI: case GL_RG: case GL_BGRA_EXT: case GL_RGBA: clientBufferFormat = attribList[1]; break; default: return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); } break; case EGL_TEXTURE_TYPE_ANGLE: switch(attribList[1]) { case GL_UNSIGNED_BYTE: case GL_UNSIGNED_SHORT: case GL_HALF_FLOAT_OES: case GL_HALF_FLOAT: clientBufferType = attribList[1]; break; default: return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); } break; case EGL_IOSURFACE_PLANE_ANGLE: if(attribList[1] < 0) { return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); } ioSurfacePlane = attribList[1]; break; case EGL_TEXTURE_TARGET: switch(attribList[1]) { case EGL_NO_TEXTURE: case EGL_TEXTURE_2D: case EGL_TEXTURE_RECTANGLE_ANGLE: textureTarget = attribList[1]; break; default: return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); } break; case EGL_MIPMAP_TEXTURE: if(attribList[1] != EGL_FALSE) { UNIMPLEMENTED(); return error(EGL_BAD_MATCH, EGL_NO_SURFACE); } break; case EGL_VG_COLORSPACE: return error(EGL_BAD_MATCH, EGL_NO_SURFACE); case EGL_VG_ALPHA_FORMAT: return error(EGL_BAD_MATCH, EGL_NO_SURFACE); default: return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); } attribList += 2; } } if(width < 0 || height < 0) { return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); } if(width == 0 || height == 0) { return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); } if((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) || (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE)) { return error(EGL_BAD_MATCH, EGL_NO_SURFACE); } if(!(configuration->mSurfaceType & EGL_PBUFFER_BIT)) { return error(EGL_BAD_MATCH, EGL_NO_SURFACE); } if(clientBuffer) { switch(clientBufferType) { case GL_UNSIGNED_BYTE: switch(clientBufferFormat) { case GL_RED: case GL_RG: case GL_BGRA_EXT: break; case GL_R16UI: case GL_RGBA: return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); default: return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); } break; case GL_UNSIGNED_SHORT: switch(clientBufferFormat) { case GL_R16UI: break; case GL_RED: case GL_RG: case GL_BGRA_EXT: case GL_RGBA: return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); default: return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); } break; case GL_HALF_FLOAT_OES: case GL_HALF_FLOAT: switch(clientBufferFormat) { case GL_RGBA: break; case GL_RED: case GL_R16UI: case GL_RG: case GL_BGRA_EXT: return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); default: return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); } break; default: return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); } if(ioSurfacePlane < 0) { return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); } if(textureFormat != EGL_TEXTURE_RGBA) { return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); } if(textureTarget != EGL_TEXTURE_RECTANGLE_ANGLE) { return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); } #if defined(__APPLE__) IOSurfaceRef ioSurface = reinterpret_cast<IOSurfaceRef>(clientBuffer); size_t planeCount = IOSurfaceGetPlaneCount(ioSurface); if((static_cast<size_t>(width) > IOSurfaceGetWidthOfPlane(ioSurface, ioSurfacePlane)) || (static_cast<size_t>(height) > IOSurfaceGetHeightOfPlane(ioSurface, ioSurfacePlane)) || ((planeCount != 0) && static_cast<size_t>(ioSurfacePlane) >= planeCount)) { return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); } #endif } else { if((textureFormat == EGL_TEXTURE_RGB && configuration->mBindToTextureRGB != EGL_TRUE) || ((textureFormat == EGL_TEXTURE_RGBA && configuration->mBindToTextureRGBA != EGL_TRUE))) { return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); } } Surface *surface = new PBufferSurface(this, configuration, width, height, textureFormat, textureTarget, clientBufferFormat, clientBufferType, largestPBuffer, clientBuffer, ioSurfacePlane); if(!surface->initialize()) { surface->release(); return EGL_NO_SURFACE; } surface->addRef(); mSurfaceSet.insert(surface); return success(surface); }