Skip to content

Instantly share code, notes, and snippets.

@Const-me
Created March 30, 2021 09:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Const-me/3730690e0aca09705030f415686f074c to your computer and use it in GitHub Desktop.
Save Const-me/3730690e0aca09705030f415686f074c to your computer and use it in GitHub Desktop.
#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