Created
March 30, 2021 09:35
-
-
Save Const-me/3730690e0aca09705030f415686f074c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "pch.h" | |
#include "RenderDeviceGLImpl.hpp" | |
#include "../../../../NetCore/ModeSet/API/eglContext.h" | |
#include <EGL/egl.h> | |
#include <EGL/eglext.h> | |
#define GL_GLEXT_PROTOTYPES | |
#include <GLES2/gl2.h> | |
#include <GLES2/gl2ext.h> | |
#include <libdrm/drm_fourcc.h> | |
#include <string> | |
#include "DeviceContextGLImpl.hpp" | |
#include "Texture2D_OGL.hpp" | |
using namespace NetCore; | |
using namespace Diligent; | |
using namespace DiligentLogger; | |
using namespace std::string_literals; | |
namespace | |
{ | |
struct EglFunctions | |
{ | |
PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR; | |
PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR; | |
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES; | |
operator bool() const | |
{ | |
return nullptr != eglCreateImageKHR && nullptr != eglDestroyImageKHR && nullptr != glEGLImageTargetTexture2DOES; | |
} | |
static const EglFunctions& instance() | |
{ | |
static const EglFunctions result; | |
return result; | |
} | |
private: | |
EglFunctions() | |
{ | |
eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC)eglGetProcAddress( "eglCreateImageKHR" ); | |
eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC)eglGetProcAddress( "eglDestroyImageKHR" ); | |
glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)eglGetProcAddress( "glEGLImageTargetTexture2DOES" ); | |
} | |
}; | |
} | |
constexpr uint32_t bindTarget = GL_TEXTURE_EXTERNAL_OES; | |
namespace NetCore | |
{ | |
enum struct eVideoColorSpace : uint8_t | |
{ | |
REC601, | |
REC709, | |
REC2020, | |
}; | |
enum struct eRange : uint8_t | |
{ | |
Full, | |
Narrow | |
}; | |
enum struct eChromaSiting : uint8_t | |
{ | |
Zero, | |
PointFive | |
}; | |
struct sColorFormat | |
{ | |
eVideoColorSpace colorSpace; | |
eRange range; | |
eChromaSiting horiz, vert; | |
}; | |
} | |
struct sEglColor | |
{ | |
int colorSpace, range, horiz, vert; | |
}; | |
static int makeSiting( NetCore::eChromaSiting s ) | |
{ | |
switch( s ) | |
{ | |
case eChromaSiting::Zero: | |
return EGL_YUV_CHROMA_SITING_0_EXT; | |
case eChromaSiting::PointFive: | |
return EGL_YUV_CHROMA_SITING_0_5_EXT; | |
} | |
logError( "Unexpected chroma siting value %i", (int)s ); | |
throw E_INVALIDARG; | |
} | |
static sEglColor makeColor( const NetCore::sColorFormat& colorFormat ) | |
{ | |
using namespace NetCore; | |
sEglColor res; | |
switch( colorFormat.colorSpace ) | |
{ | |
case eVideoColorSpace::REC601: | |
res.colorSpace = EGL_ITU_REC601_EXT; | |
break; | |
case eVideoColorSpace::REC709: | |
res.colorSpace = EGL_ITU_REC709_EXT; | |
break; | |
case eVideoColorSpace::REC2020: | |
res.colorSpace = EGL_ITU_REC2020_EXT; | |
break; | |
default: | |
logError( "Unexpected color space value %i", (int)colorFormat.colorSpace ); | |
throw E_INVALIDARG; | |
} | |
switch( colorFormat.range ) | |
{ | |
case eRange::Full: | |
res.range = EGL_YUV_FULL_RANGE_EXT; | |
break; | |
case eRange::Narrow: | |
res.range = EGL_YUV_NARROW_RANGE_EXT; | |
break; | |
default: | |
logError( "Unexpected range value %i", (int)colorFormat.range ); | |
throw E_INVALIDARG; | |
} | |
res.horiz = makeSiting( colorFormat.horiz ); | |
res.vert = makeSiting( colorFormat.vert ); | |
return res; | |
} | |
HRESULT COMLIGHTCALL RenderDeviceGLImpl::importNv12Texture( NetCore::iTexture** result, const NetCore::sDmaBuffer &dma, const NetCore::sColorFormat& colorFormat ) noexcept | |
{ | |
if( result == nullptr ) | |
return E_POINTER; | |
sEglColor color; | |
try | |
{ | |
color = makeColor( colorFormat ); | |
} | |
catch( HRESULT hr ) | |
{ | |
return hr; | |
} | |
sEglContext context = getThreadEglContext(); | |
if( nullptr == context.context || nullptr == context.display ) | |
{ | |
logError( u8"The current thread doesn’t have a EGL context; iGlesTexture.exportDmaBuffer API only works on the GUI thread." ); | |
return OLE_E_BLANK; | |
} | |
const EglFunctions& functions = EglFunctions::instance(); | |
if( !functions ) | |
{ | |
logError( "The required extensions, EGL_KHR_image_base and GL_OES_EGL_image, aren’t supported by GPU driver" ); | |
return E_FAIL; | |
} | |
EGLint attrib_list[] = { | |
EGL_WIDTH, dma.sizePixels.cx, | |
EGL_HEIGHT, dma.sizePixels.cy, | |
EGL_LINUX_DRM_FOURCC_EXT, DRM_FORMAT_NV12, | |
EGL_YUV_COLOR_SPACE_HINT_EXT, color.colorSpace, | |
EGL_SAMPLE_RANGE_HINT_EXT, color.range, | |
EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT, color.horiz, | |
EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT, color.vert, | |
EGL_DMA_BUF_PLANE0_FD_EXT, dma.fd, | |
EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0, | |
EGL_DMA_BUF_PLANE0_PITCH_EXT, dma.stride, | |
EGL_DMA_BUF_PLANE1_FD_EXT, dma.fd, | |
EGL_DMA_BUF_PLANE1_OFFSET_EXT, dma.stride * dma.sizePixels.cy, | |
EGL_DMA_BUF_PLANE1_PITCH_EXT, dma.stride, | |
EGL_NONE, | |
}; | |
EGLImageKHR egl_image = functions.eglCreateImageKHR( | |
context.display, | |
EGL_NO_CONTEXT, | |
EGL_LINUX_DMA_BUF_EXT, | |
NULL, | |
attrib_list ); | |
if( EGL_NO_IMAGE_KHR == egl_image ) | |
{ | |
logError( "eglCreateImageKHR failed: %s", eglFormatMessage( eglGetError() ) ); | |
return E_FAIL; | |
} | |
try | |
{ | |
std::string textureName = formatStdString( "Video frame #%i", dma.bufferIndex ); | |
logVerbose( u8"%s: imported DMA buffer, %i×%i pixels", textureName.c_str(), dma.sizePixels.cx, dma.sizePixels.cy ); | |
GLObjectWrappers::GLTextureObj glTexture{ true }; | |
DeviceContextGLImpl& ctx = *static_cast<DeviceContextGLImpl*>( GetImmediateContext().RawPtr() ); | |
GLContextState& state = ctx.getState(); | |
state.BindTexture( 0, bindTarget, glTexture ); | |
functions.glEGLImageTargetTexture2DOES( bindTarget, egl_image ); | |
uint32_t err = glGetError(); | |
if( err != GL_NO_ERROR ) | |
{ | |
const std::string es = glGetErrorString( err ); | |
logError( "glEGLImageTargetTexture2DOES failed%s", es.c_str() ); | |
return E_FAIL; | |
} | |
TextureDesc desc; | |
desc.Name = textureName.c_str(); | |
desc.Type = RESOURCE_DIM_TEX_2D; | |
desc.Width = (uint32_t)dma.sizePixels.cx; | |
desc.Height = (uint32_t)dma.sizePixels.cy; | |
desc.BindFlags = BIND_SHADER_RESOURCE; | |
desc.MiscFlags = MISC_TEXTURE_FLAG_EXTERNAL; | |
desc.Format = TEX_FORMAT_RGBA8_UNORM; // That's not true BTW, but hopefully good enough for the shader views. | |
RefCntAutoPtr<Diligent::ITexture> texture; | |
CreateTextureFromGLHandle( glTexture, desc, RESOURCE_STATE_UNDEFINED, &texture ); | |
*result = static_cast<Texture2D_OGL*>( texture.Detach() ); | |
const uint32_t gle = glGetError(); | |
if( 0 != gle ) | |
{ | |
logError( "%s: error creating GL texture; %s", textureName.c_str(), glGetErrorString( gle ).c_str() ); | |
return E_FAIL; | |
} | |
logVerbose( "%s: created GLES texture; GL handle %i", textureName.c_str(), glTexture.operator GLuint() ); | |
glTexture.detach(); | |
return S_OK; | |
} | |
catch( const std::exception& ex ) | |
{ | |
logError( "Failed: %s", ex.what() ); | |
return E_FAIL; | |
} | |
catch( HRESULT hr ) | |
{ | |
return hr; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment