unity_native_render_plugin/NativeRenderPlugin/RenderAPI_OpenGLCoreES.cpp
2025-04-24 10:48:58 +08:00

444 lines
13 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "RenderAPI.h"
#include "PlatformBase.h"
#include <stdio.h>
// OpenGL Core profile (desktop) or OpenGL ES (mobile) implementation of RenderAPI.
// Supports several flavors: Core, ES2, ES3
#if SUPPORT_OPENGL_UNIFIED
#include "Unity/IUnityRenderingExtensions.h"
#include <assert.h>
#if UNITY_IOS || UNITY_TVOS
#include <OpenGLES/ES2/gl.h>
#elif UNITY_ANDROID || UNITY_WEBGL || OHOS
#define GL_GLEXT_PROTOTYPES
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <EGL/egl.h>
#if OHOS
#include <xengine/xeg_gles_extension.h>
#include "xengine/xeg_gles_spatial_upscale.h"
#include "xengine/xeg_gles_adaptive_vrs.h"
#include "xengine/xeg_gles_neural_upscale.h"
#include <native_buffer/native_buffer.h>
#include <native_window/external_window.h>
#include <graphics_game_sdk/frame_generation_gles.h>
#endif
#elif UNITY_OSX
#include <OpenGL/gl3.h>
#elif UNITY_WIN
// On Windows, use gl3w to initialize and load OpenGL Core functions. In principle any other
// library (like GLEW, GLFW etc.) can be used; here we use gl3w since it's simple and
// straightforward.
#include "gl3w/gl3w.h"
#elif UNITY_LINUX
#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
#elif UNITY_EMBEDDED_LINUX
#include <GLES2/gl2.h>
#if SUPPORT_OPENGL_CORE
#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
#endif
#elif UNITY_QNX
#include <GLES2/gl2.h>
#else
#error Unknown platform
#endif
#include <string.h>
extern void unityLog(const char *msg);
typedef void(GL_APIENTRYP PFNGLSHADINGRATE)(GLenum rate);
typedef void (GL_APIENTRYP PFNGLQCOMFRAMEEXTRAPOLATION) (GLuint src1, GLuint src2, GLuint output, float scaleFactor);
class RenderAPI_OpenGLCoreES : public RenderAPI
{
public:
RenderAPI_OpenGLCoreES(UnityGfxRenderer api_type);
virtual ~RenderAPI_OpenGLCoreES() {}
virtual void processDeviceEvent(UnityGfxDeviceEventType type, IUnityInterfaces *interfaces) override;
virtual bool getUsesReverseZ() override { return false; }
virtual void enableVRS(void* data) override;
virtual void disableVRS() override;
virtual void enableFGExtrapolation(void* data) override;
virtual void preFGExtrapolation() override;
virtual bool doFGExtrapolation(void *src, void *data, void *dst) override;
virtual void postFGExtrapolation() override;
virtual void disableFGExtrapolation() override;
virtual void spatialUpScale(void *data) override;
private:
virtual void initSupportFeature() override;
UnityGfxRenderer m_api_type;
PFNGLSHADINGRATE gl_shadingrate_fn = nullptr;
PFNGLQCOMFRAMEEXTRAPOLATION gl_extrapolate_qcom_fn;
#if OHOS
FG_Context_GLES* hw_fg_context;
#endif
};
// 重新定义 vrs rate
/*
QCOM_shading_rate
SHADING_RATE_1X1_PIXELS_QCOM 0x96A6
SHADING_RATE_1X2_PIXELS_QCOM 0x96A7
SHADING_RATE_2X1_PIXELS_QCOM 0x96A8
SHADING_RATE_2X2_PIXELS_QCOM 0x96A9
SHADING_RATE_4X2_PIXELS_QCOM 0x96AC
SHADING_RATE_4X4_PIXELS_QCOM 0x96AE
*/
#define SHADING_RATE_1X1_PIXELS_EXT 0x96A6
#define SHADING_RATE_1X2_PIXELS_EXT 0x96A7
#define SHADING_RATE_2X1_PIXELS_EXT 0x96A8
#define SHADING_RATE_2X2_PIXELS_EXT 0x96A9
#define SHADING_RATE_1X4_PIXELS_EXT 0x96AA
#define SHADING_RATE_4X1_PIXELS_EXT 0x96AB
#define SHADING_RATE_4X2_PIXELS_EXT 0x96AC
#define SHADING_RATE_2X4_PIXELS_EXT 0x96AD
#define SHADING_RATE_4X4_PIXELS_EXT 0x96AE
// TODO: glGetFragmentShadingRatesEXT 检查支持的项
static GLenum vrs_argment_size_table[] =
{
SHADING_RATE_1X1_PIXELS_EXT,
SHADING_RATE_2X1_PIXELS_EXT,
SHADING_RATE_1X2_PIXELS_EXT,
SHADING_RATE_2X2_PIXELS_EXT,
SHADING_RATE_4X2_PIXELS_EXT,
SHADING_RATE_2X4_PIXELS_EXT,
SHADING_RATE_4X4_PIXELS_EXT,
// SHADING_RATE_1X4_PIXELS_EXT, //(此硬件原生不支持)
// SHADING_RATE_4X1_PIXELS_EXT,// (此硬件原生不支持)
};
#define GL_DRAWCALL_HINT 0x8193
#define GL_START 0x8194
#define GL_END 0x8195
RenderAPI *CreateRenderAPI_OpenGLCoreES(UnityGfxRenderer api_type)
{
return new RenderAPI_OpenGLCoreES(api_type);
}
RenderAPI_OpenGLCoreES::RenderAPI_OpenGLCoreES(UnityGfxRenderer api_type)
: m_api_type(api_type)
{
}
void RenderAPI_OpenGLCoreES::processDeviceEvent(UnityGfxDeviceEventType type, IUnityInterfaces *interfaces)
{
if (type == kUnityGfxDeviceEventInitialize)
{
initSupportFeature();
}
else if (type == kUnityGfxDeviceEventShutdown)
{
//@TODO: release resources
}
}
void RenderAPI_OpenGLCoreES::initSupportFeature()
{
#ifdef GL_EXT_fragment_shading_rate
support_features[GraphicsFeature::VRS_DRAW] = true;
gl_shadingrate_fn = glShadingRateEXT;
#endif // GL_EXT_fragment_shading_rate
#ifdef GL_EXT_fragment_shading_rate_primitive
support_features[GraphicsFeature::VRS_PRIMITIVE] = true;
#endif // GL_EXT_fragment_shading_rate_primitive
#ifdef GL_EXT_fragment_shading_rate_attachment
support_features[GraphicsFeature::VRS_ATTACHMENT] = true;
#endif // GL_EXT_fragment_shading_rate_attachment
const char *extensions = (const char *)glGetString(GL_EXTENSIONS);
if (strstr(extensions, "GL_EXT_fragment_shading_rate") || strstr(extensions, "GL_QCOM_shading_rate"))
{
support_features[GraphicsFeature::VRS_DRAW] = true;
}
if (strstr(extensions, "GL_EXT_fragment_shading_rate_primitive"))
{
support_features[GraphicsFeature::VRS_PRIMITIVE] = true;
}
if (strstr(extensions, "GL_EXT_fragment_shading_rate_attachment"))
{
support_features[GraphicsFeature::VRS_ATTACHMENT] = true;
}
if (support_features[GraphicsFeature::VRS_DRAW])
{
if (gl_shadingrate_fn == nullptr)
{
gl_shadingrate_fn = (PFNGLSHADINGRATE)((void *)eglGetProcAddress("glShadingRateQCOM"));
if (gl_shadingrate_fn == nullptr)
{
gl_shadingrate_fn = (PFNGLSHADINGRATE)((void *)eglGetProcAddress("glShadingRateEXT"));
if (gl_shadingrate_fn == nullptr)
{
support_features[GraphicsFeature::VRS_DRAW] = false;
}
}
}
}
if (strstr(extensions, "GL_QCOM_frame_extrapolation"))
{
support_features[GraphicsFeature::QCOM_AFME] = true;
gl_extrapolate_qcom_fn = (PFNGLQCOMFRAMEEXTRAPOLATION)eglGetProcAddress("glExtrapolateTex2DQCOM");
}
#if OHOS
extensions = (const char *)HMS_XEG_GetString(XEG_EXTENSIONS);
if (strstr(extensions, XEG_SPATIAL_UPSCALE_EXTENSION_NAME))
{
support_features[GraphicsFeature::HW_SPATIAL_SR] = true;
}
if (strstr(extensions, XEG_NEURAL_UPSCALE_EXTENSION_NAME))
{
support_features[GraphicsFeature::HW_AI_SPATIAL_SR] = true;
}
if (strstr(extensions, XEG_ADAPTIVE_VRS_EXTENSION_NAME))
{
support_features[GraphicsFeature::HW_ADAPTIVE_VRS] = true;
}
#endif
char buf[40];
for (size_t i = 0; i < GraphicsFeature::MAX_CNT; i++)
{
sprintf(buf, "GraphicsFeature: %d \n", support_features[(GraphicsFeature)i]);
unityLog(buf);
}
}
void RenderAPI_OpenGLCoreES::enableVRS(void* data)
{
int vrs_enum = *(int*) data;
gl_shadingrate_fn(vrs_argment_size_table[vrs_enum]);
}
void RenderAPI_OpenGLCoreES::disableVRS()
{
gl_shadingrate_fn(vrs_argment_size_table[0]);
}
void RenderAPI_OpenGLCoreES::enableFGExtrapolation(void* data)
{
#if OHOS
struct RenderResultion
{
uint32_t width;
uint32_t heigh;
};
auto resultion_param = static_cast<RenderResultion*>(data);
hw_fg_context = HMS_FG_CreateContext_GLES();
// 初始化超帧接口调用错误码
FG_ErrorCode error_code = FG_SUCCESS;
// 超帧算法模式
FG_AlgorithmModeInfo algorith_info{};
algorith_info.predictionMode = FG_PREDICTION_MODE_EXTRAPOLATION; // 外插模式
algorith_info.meMode = FG_ME_MODE_BASIC; // 运动估计基础模式
error_code = HMS_FG_SetAlgorithmMode_GLES(hw_fg_context, &algorith_info); // [必选] 设置超帧算法模式
if (error_code != FG_SUCCESS)
{
return;
}
// 超帧输入输出图像分辨率
FG_ResolutionInfo resolution_info{};
resolution_info.inputColorResolution = FG_Dimension2D{resultion_param->width,resultion_param->heigh};
resolution_info.inputDepthStencilResolution = FG_Dimension2D{resultion_param->width,resultion_param->heigh};
resolution_info.outputColorResolution = FG_Dimension2D{resultion_param->width,resultion_param->heigh};
error_code = HMS_FG_SetResolution_GLES(hw_fg_context, &resolution_info); // [必选] 设置超帧输入输出图像分辨率
if (error_code != FG_SUCCESS)
{
return;
}
// [可选] 设置齐次裁剪空间Z/W范围及深度测试模式接口不调用时默认为FG_CVV_Z_SEMANTIC_MINUS_ONE_TO_ONE_FORWARD_Z
error_code = HMS_FG_SetCvvZSemantic_GLES(hw_fg_context, FG_CVV_Z_SEMANTIC_MINUS_ONE_TO_ONE_FORWARD_Z);
if (error_code != FG_SUCCESS)
{
return;
}
// [可选] 设置真实渲染帧颜色缓冲区图像格式接口不调用时默认为FG_FORMAT_R8G8B8A8_UNORM
error_code = HMS_FG_SetImageFormat_GLES(hw_fg_context, FG_FORMAT_R8G8B8A8_UNORM);
if (error_code != FG_SUCCESS)
{
return;
}
// [可选] 当颜色缓冲区相对深度模板缓冲区基于y轴翻转180度时设置第二个参数为true接口不调用时默认为无翻转
error_code = HMS_FG_SetDepthStencilYDirectionInverted_GLES(hw_fg_context, true);
if (error_code != FG_SUCCESS)
{
return;
}
#endif
}
void RenderAPI_OpenGLCoreES::preFGExtrapolation()
{
#if OHOS
HMS_FG_Activate_GLES(hw_fg_context);
// glHint(GL_DRAWCALL_HINT, GL_START); // 绘制动态物体前,开始记录顶点数据
#endif
}
bool RenderAPI_OpenGLCoreES::doFGExtrapolation(void *src, void *data, void *dst)
{
#if OHOS
struct HWFGExtrapolationParam
{
FG_Mat4x4 pre_view_proj;
FG_Mat4x4 pre_in_view_proj;
void* depth_stencil_tex;
};
FG_DispatchDescription_GLES dispatch_description_data {
.inputColor = 0U,
.inputDepthStencil = 0U,
.viewProj{},
.invViewProj{},
.outputColor = 0U
};
auto param = static_cast<HWFGExtrapolationParam*>(data);
GLuint gl_srctex = (GLuint)(size_t)(src);
GLuint gl_dsttex = (GLuint)(size_t)(dst);
GLuint gl_depth_stencil_tex = (GLuint)(size_t)(param->depth_stencil_tex);
// 传入上一帧真实渲染帧颜色缓冲区索引
dispatch_description_data.inputColor = gl_srctex;
// 传入上一帧真实渲染帧深度模板缓冲区索引
dispatch_description_data.inputDepthStencil = gl_depth_stencil_tex;
// 传入预测帧缓冲区索引
dispatch_description_data.outputColor = gl_dsttex;
// 传入上一帧真实渲染帧视图投影矩阵
dispatch_description_data.viewProj = param->pre_view_proj;
// 传入上一帧真实渲染帧视图投影逆矩阵
dispatch_description_data.invViewProj = param->pre_in_view_proj;
// // [可选] 当视图投影矩阵的平移分量非常大时,可提供相机扩展属性信息以获得更加准确的超帧效果。
// FG_PerFrameExtendedCameraInfo info;
// auto error_code = HMS_FG_SetExtendedCameraInfo_GLES(hw_fg_context, &info);
// 生成预测帧,更新预测帧缓冲区的内存
auto error_code = HMS_FG_Dispatch_GLES(hw_fg_context, &dispatch_description_data);
switch (error_code)
{
case FG_SUCCESS:
{
// 绘制预测帧
// ...
// 绘制UI
// ...
// 送显预测帧
// ...
break;
}
case FG_COLLECTING_PREVIOUS_FRAMES:
// 传入真实帧数量未达到固定阈值,无预测帧生成,基础外插模式传入真实帧数量<3时返回该状态码增强外插模式传入真实帧数量<2时返回该状态码此时不要将预测帧送显
break;
default:
// 预测帧生成失败
return false;
}
return true;
#else
GLuint gl_src0tex = (GLuint)(size_t)(src);
GLuint gl_src1tex = (GLuint)(size_t)(data);
GLuint gl_dsttex = (GLuint)(size_t)(dst);
gl_extrapolate_qcom_fn(gl_src0tex, gl_src1tex, gl_dsttex, 0.5f);
auto err = glGetError();
return err == GL_NO_ERROR;
#endif
}
void RenderAPI_OpenGLCoreES::postFGExtrapolation()
{
#if OHOS
// glHint(GL_DRAWCALL_HINT, GL_END); // 绘制动态物体后,结束记录顶点数据
#endif
}
void RenderAPI_OpenGLCoreES::disableFGExtrapolation()
{
#if OHOS
auto error_code = HMS_FG_DestroyContext_GLES(&hw_fg_context);
if (error_code != FG_SUCCESS)
{
return;
}
#endif
}
void RenderAPI_OpenGLCoreES::spatialUpScale(void *data)
{
#if OHOS
struct DataPack
{
void* src;
void* data;
void* dst;
};
struct HWSpatialSRParam
{
float sharpness;
uint32_t render_width;
uint32_t render_height;
uint32_t upscale_width;
uint32_t upscale_height;
};
DataPack* data_pack = static_cast<DataPack*>(data);
if (data_pack->data != NULL)
{
HWSpatialSRParam* param = (HWSpatialSRParam*) data_pack->data;
float m_sharpness = param->sharpness;
HMS_XEG_SpatialUpscaleParameter(XEG_SPATIAL_UPSCALE_SHARPNESS, &m_sharpness);
// upscaleScissor为超分输入图像的采样区域
int upscaleScissor[4] = {0, 0, static_cast<int>(param->render_width), static_cast<int>(param->render_height)};
HMS_XEG_SpatialUpscaleParameter(XEG_SPATIAL_UPSCALE_SCISSOR, upscaleScissor);
GLuint gl_srctex = (GLuint)(size_t)(data_pack->src);
// TODO: 测试由上层设置
GLuint gl_dsttex = (GLuint)(size_t)(data_pack->dst);
// // upscaleFBO为用户自定义创建的framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, gl_dsttex);
glViewport(0, 0, param->upscale_width, param->upscale_height);
glScissor(0, 0, param->upscale_width, param->upscale_height);
HMS_XEG_RenderSpatialUpscale(gl_srctex);
}
#endif
}
#endif // #if SUPPORT_OPENGL_UNIFIED