#include "RenderAPI.h" #include "PlatformBase.h" #include // 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 #if UNITY_IOS || UNITY_TVOS #include #elif UNITY_ANDROID || UNITY_WEBGL || OHOS #define GL_GLEXT_PROTOTYPES #include #include #include #if OHOS #include #include "xengine/xeg_gles_spatial_upscale.h" #include "xengine/xeg_gles_adaptive_vrs.h" #include "xengine/xeg_gles_neural_upscale.h" #include #include #include #endif #elif UNITY_OSX #include #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 #elif UNITY_EMBEDDED_LINUX #include #if SUPPORT_OPENGL_CORE #define GL_GLEXT_PROTOTYPES #include #endif #elif UNITY_QNX #include #else #error Unknown platform #endif #include 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(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(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(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(param->render_width), static_cast(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