public Cubemap GetReflectionCubemap(IntPtr sessionHandle, IntPtr lightEstimateHandle)
        {
            int  size = 0;
            bool usingGammaWorkflow = QualitySettings.activeColorSpace == ColorSpace.Gamma;

#if UNITY_2017_2_OR_NEWER
            // Cubemap.CreateExternalTexture only exists in Unity 2017 above.
            int textureId = 0;
            ApiTextureDataType dataType =
                SystemInfo.graphicsDeviceType == GraphicsDeviceType.OpenGLES3 ?
                ApiTextureDataType.Half : ApiTextureDataType.Byte;
            TextureFormat format = dataType == ApiTextureDataType.Half ?
                                   TextureFormat.RGBAHalf : TextureFormat.RGBA32;

            if (!_pluginInitialized)
            {
                ExternApi.ARCoreRenderingUtils_SetTextureDataType(dataType, true);
                ExternApi.ARCoreRenderingUtils_SetActiveColorSpace(usingGammaWorkflow);
                _pluginInitialized = true;
            }

            ExternApi.ARCoreRenderingUtils_GetCubemapTexture(ref textureId, ref size);
            if (textureId != 0 && (_hdrCubemap == null || textureId != _cubemapTextureId))
            {
                _hdrCubemap = Cubemap.CreateExternalTexture(size, format, true,
                                                            new IntPtr(textureId));
                _cubemapTextureId = textureId;
            }

            long timestamp = GetTimestamp(sessionHandle, lightEstimateHandle);
            if (_cubemapTimestamp != timestamp)
            {
                ExternApi.ARCoreRenderingUtils_SetARCoreLightEstimation(sessionHandle,
                                                                        lightEstimateHandle);
                _cubemapTimestamp = timestamp;
            }

            // Issue plugin event to update cubemap texture.
            GL.IssuePluginEvent(ExternApi.ARCoreRenderingUtils_GetRenderEventFunc(),
                                (int)ApiRenderEvent.UpdateCubemapTexture);
#else
            // Gets raw color data from native plugin then update cubemap textures by
            // Cubemap.SetPixel().
            // Note, no GL texture will be created in this scenario.
            if (!_pluginInitialized)
            {
                ExternApi.ARCoreRenderingUtils_SetTextureDataType(
                    ApiTextureDataType.Float, false);
                ExternApi.ARCoreRenderingUtils_SetActiveColorSpace(usingGammaWorkflow);
                _pluginInitialized = true;
            }

            ExternApi.ARCoreRenderingUtils_GetCubemapTexture(ref _cubemapTextureId, ref size);
            if (size > 0)
            {
                if (_hdrCubemap == null)
                {
                    _hdrCubemap = new Cubemap(size, TextureFormat.RGBAHalf, true);
                }

                if (_tempCubemapFacePixels.Length != size)
                {
                    Array.Resize(ref _tempCubemapFacePixels, size * size);
                }
            }

            long timestamp = GetTimestamp(sessionHandle, lightEstimateHandle);
            if (_cubemapTimestamp != timestamp)
            {
                ExternApi.ARCoreRenderingUtils_SetARCoreLightEstimation(sessionHandle,
                                                                        lightEstimateHandle);
                _cubemapTimestamp = timestamp;

                if (_hdrCubemap != null)
                {
                    for (int i = 0; i < 6; i++)
                    {
                        ExternApi.ARCoreRenderingUtils_GetCubemapRawColors(i,
                                                                           _tempCubemapFacePixels);
                        _hdrCubemap.SetPixels(_tempCubemapFacePixels, CubemapFace.PositiveX + i);
                    }

                    // This operation is very expensive, only update cubemap texture when
                    // the light estimate is updated in this frame.
                    _hdrCubemap.Apply();
                }
            }
#endif

            return(_hdrCubemap);
        }