From eac016fcf883b22a9f2e2810a9124c3f0170169f Mon Sep 17 00:00:00 2001 From: korenkonder Date: Wed, 29 Jan 2025 01:34:08 +0300 Subject: [PATCH] NVENC: Handle color conversion by ourself on GPU --- src/CRE/shader_dev.cpp | 90 ++++++++ src/CRE/shader_dev.hpp | 4 + src/ReDIVA/video/nvenc/nvenc_encoder.cpp | 8 +- src/ReDIVA/x_pv_game.cpp | 248 +++++++++++------------ 4 files changed, 216 insertions(+), 134 deletions(-) diff --git a/src/CRE/shader_dev.cpp b/src/CRE/shader_dev.cpp index 3a34ec7c..e7a1e201 100644 --- a/src/CRE/shader_dev.cpp +++ b/src/CRE/shader_dev.cpp @@ -11,12 +11,39 @@ enum shader_dev_sub_enum { SHADER_DEV_SUB_SHADER_FFP = 0, + SHADER_DEV_SUB_CONVERT_YCBCR_BT709, + SHADER_DEV_SUB_CONVERT_RGB, + SHADER_DEV_SUB_CONVERT_ALPHA, #if DISPLAY_IBL SHADER_DEV_SUB_CUBEMAP_DISPLAY, #endif SHADER_DEV_SUB_SHADER_END, }; +static const int32_t convert_ycbcr_bt709_vpt_unival_max[] = { + -1, +}; + +static const int32_t convert_ycbcr_bt709_fpt_unival_max[] = { + -1, +}; + +static const int32_t convert_alpha_vpt_unival_max[] = { + -1, +}; + +static const int32_t convert_alpha_fpt_unival_max[] = { + -1, +}; + +static const int32_t convert_rgb_vpt_unival_max[] = { + -1, +}; + +static const int32_t convert_rgb_fpt_unival_max[] = { + -1, +}; + #if DISPLAY_IBL static const int32_t cubemap_display_vpt_unival_max[] = { -1, @@ -44,6 +71,39 @@ static const int32_t cubemap_display_fpt_unival_max[] = { #define SHADER_DESCRIPTION_COMMON_QUAD \ { SHADER_DESCRIPTION_UNIFORM, 0, sizeof(quad_shader_data), U_INVALID, } +static const shader_description convert_ycbcr_bt709_vpt_desc[] = { + SHADER_DESCRIPTION_COMMON_QUAD, + { SHADER_DESCRIPTION_END, -1, -1, U_INVALID, }, +}; + +static const shader_description convert_ycbcr_bt709_fpt_desc[] = { + { SHADER_DESCRIPTION_SAMPLER, 0, 0, U_INVALID, }, + { SHADER_DESCRIPTION_FRAGMENT_OUTPUT, 0, 4, U_INVALID, }, + { SHADER_DESCRIPTION_END, -1, -1, U_INVALID, }, +}; + +static const shader_description convert_alpha_vpt_desc[] = { + SHADER_DESCRIPTION_COMMON_QUAD, + { SHADER_DESCRIPTION_END, -1, -1, U_INVALID, }, +}; + +static const shader_description convert_alpha_fpt_desc[] = { + { SHADER_DESCRIPTION_SAMPLER, 0, 0, U_INVALID, }, + { SHADER_DESCRIPTION_FRAGMENT_OUTPUT, 0, 4, U_INVALID, }, + { SHADER_DESCRIPTION_END, -1, -1, U_INVALID, }, +}; + +static const shader_description convert_rgb_vpt_desc[] = { + SHADER_DESCRIPTION_COMMON_QUAD, + { SHADER_DESCRIPTION_END, -1, -1, U_INVALID, }, +}; + +static const shader_description convert_rgb_fpt_desc[] = { + { SHADER_DESCRIPTION_SAMPLER, 0, 0, U_INVALID, }, + { SHADER_DESCRIPTION_FRAGMENT_OUTPUT, 0, 4, U_INVALID, }, + { SHADER_DESCRIPTION_END, -1, -1, U_INVALID, }, +}; + #if DISPLAY_IBL static const shader_description cubemap_display_vpt_desc[] = { { SHADER_DESCRIPTION_VERTEX_INPUT, 0, 3, U_INVALID, }, @@ -65,6 +125,18 @@ static const shader_description cubemap_display_fpt_desc[] = { #undef SHADER_DESCRIPTION_EFFECT_TEXTURE_SAMPLER #pragma endregion +static const uniform_name CONVERT_YCBCR_BT709_uniform[] = { + U_INVALID, +}; + +static const uniform_name CONVERT_ALPHA_uniform[] = { + U_INVALID, +}; + +static const uniform_name CONVERT_RGB_uniform[] = { + U_INVALID, +}; + #if DISPLAY_IBL static const uniform_name CUBEMAP_DISPLAY_uniform[] = { U_INVALID, @@ -82,6 +154,21 @@ static const uniform_name CUBEMAP_DISPLAY_uniform[] = { fp##_fpt_desc, \ } +static const shader_sub_table CONVERT_YCBCR_BT709_table[] = { + shader_sub_table_struct(CONVERT_YCBCR_BT709, + convert_ycbcr_bt709, convert_ycbcr_bt709), +}; + +static const shader_sub_table CONVERT_ALPHA_table[] = { + shader_sub_table_struct(CONVERT_ALPHA, + convert_alpha, convert_alpha), +}; + +static const shader_sub_table CONVERT_RGB_table[] = { + shader_sub_table_struct(CONVERT_RGB, + convert_rgb, convert_rgb), +}; + #if DISPLAY_IBL static const shader_sub_table CUBEMAP_DISPLAY_table[] = { shader_sub_table_struct(CUBEMAP_DISPLAY, @@ -110,6 +197,9 @@ const shader_table shader_dev_table[] = { 0, 0, }, + shader_table_struct(CONVERT_YCBCR_BT709), + shader_table_struct(CONVERT_ALPHA), + shader_table_struct(CONVERT_RGB), #if DISPLAY_IBL shader_table_struct(CUBEMAP_DISPLAY), #endif diff --git a/src/CRE/shader_dev.hpp b/src/CRE/shader_dev.hpp index 9af4e76c..c5dc45b8 100644 --- a/src/CRE/shader_dev.hpp +++ b/src/CRE/shader_dev.hpp @@ -11,6 +11,10 @@ enum shader_dev_enum { SHADER_DEV_FFP = 0, + SHADER_DEV_CONVERT_YCBCR_BT709, + SHADER_DEV_CONVERT_ALPHA, + SHADER_DEV_CONVERT_RGB, + SHADER_DEV_CONVERT_YCGCO, #if DISPLAY_IBL SHADER_DEV_CUBEMAP_DISPLAY, #endif diff --git a/src/ReDIVA/video/nvenc/nvenc_encoder.cpp b/src/ReDIVA/video/nvenc/nvenc_encoder.cpp index e996f420..b95f814d 100644 --- a/src/ReDIVA/video/nvenc/nvenc_encoder.cpp +++ b/src/ReDIVA/video/nvenc/nvenc_encoder.cpp @@ -85,7 +85,9 @@ nvenc_encoder::nvenc_encoder(int32_t width, int32_t height, is_10_bit &= support_10bit_encode; is_444 &= support_yuv444_encode; - buffer_format = is_rgb ? NV_ENC_BUFFER_FORMAT_AYUV : NV_ENC_BUFFER_FORMAT_ARGB; + is_10_bit &= !lossless; + + buffer_format = NV_ENC_BUFFER_FORMAT_ARGB; num_bframes = clamp_def(num_bframes, 0, num_max_bframes); extra_output_delay = max_def(extra_output_delay, 2); @@ -128,7 +130,7 @@ nvenc_encoder::nvenc_encoder(int32_t width, int32_t height, if (!lossless) hevc_config.useBFramesAsRef = (NV_ENC_BFRAME_REF_MODE)(support_bframe_ref_mode & NV_ENC_BFRAME_REF_MODE_MIDDLE); hevc_config.outputBitDepth = is_10_bit ? NV_ENC_BIT_DEPTH_10 : NV_ENC_BIT_DEPTH_8; - hevc_config.inputBitDepth = is_10_bit ? NV_ENC_BIT_DEPTH_10 : NV_ENC_BIT_DEPTH_8; + hevc_config.inputBitDepth = NV_ENC_BIT_DEPTH_8; hevc_config.hevcVUIParameters.videoSignalTypePresentFlag = 1; hevc_config.hevcVUIParameters.videoFormat = NV_ENC_VUI_VIDEO_FORMAT_UNSPECIFIED; hevc_config.hevcVUIParameters.videoFullRangeFlag = 1; @@ -181,7 +183,7 @@ nvenc_encoder::nvenc_encoder(int32_t width, int32_t height, tex_desc.Height = height; tex_desc.MipLevels = 1; tex_desc.ArraySize = 1; - tex_desc.Format = is_rgb ? DXGI_FORMAT_AYUV : DXGI_FORMAT_R8G8B8A8_UNORM; + tex_desc.Format = DXGI_FORMAT_AYUV; tex_desc.SampleDesc.Count = 1; tex_desc.SampleDesc.Quality = 0; tex_desc.Usage = D3D11_USAGE_DEFAULT; diff --git a/src/ReDIVA/x_pv_game.cpp b/src/ReDIVA/x_pv_game.cpp index 4010e758..3a9d0af4 100644 --- a/src/ReDIVA/x_pv_game.cpp +++ b/src/ReDIVA/x_pv_game.cpp @@ -6287,15 +6287,23 @@ struct d3d_gl_fbo_tex_struct { GLuint tex; HANDLE handle; - inline d3d_gl_fbo_tex_struct() : tex(), handle() { + inline d3d_gl_fbo_tex_struct() : fbo(), tex(), handle() { } - inline void init(ID3D11Texture2D* texture) { + inline void init(ID3D11Texture2D* texture = 0) { glGenTextures(1, &tex); - handle = wglDXRegisterObjectNV(d3d_gl_handle, texture, - tex, GL_TEXTURE_2D, WGL_ACCESS_READ_WRITE_NV); + if (GLAD_WGL_NV_DX_interop2) + handle = wglDXRegisterObjectNV(d3d_gl_handle, texture, + tex, GL_TEXTURE_2D, WGL_ACCESS_READ_WRITE_NV); + else { + gl_state_bind_texture_2d(tex); + ::texture* tex = rctx_ptr->screen_buffer.color_texture; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, + tex->width, tex->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + gl_state_bind_texture_2d(0); + } glGenFramebuffers(1, &fbo); @@ -6310,19 +6318,23 @@ struct d3d_gl_fbo_tex_struct { glDeleteFramebuffers(1, &fbo); fbo = 0; - wglDXUnregisterObjectNV(d3d_gl_handle, handle); - handle = 0; + if (GLAD_WGL_NV_DX_interop2 && handle) { + wglDXUnregisterObjectNV(d3d_gl_handle, handle); + handle = 0; + } glDeleteTextures(1, &tex); tex = 0; } inline void lock() { - wglDXLockObjectsNV(d3d_gl_handle, 1, &handle); + if (GLAD_WGL_NV_DX_interop2 && handle) + wglDXLockObjectsNV(d3d_gl_handle, 1, &handle); } inline void unlock() { - wglDXUnlockObjectsNV(d3d_gl_handle, 1, &handle); + if (GLAD_WGL_NV_DX_interop2 && handle) + wglDXUnlockObjectsNV(d3d_gl_handle, 1, &handle); } }; @@ -6339,8 +6351,8 @@ waitable_timer d3d_timer; static const size_t nvenc_src_pixel_size = 4; static const size_t nvenc_dst_pixel_size = 4; -static nvenc_encoder_format nvenc_format; -static bool nvenc_lossless; +static nvenc_encoder_format nvenc_format = NVENC_ENCODER_YUV420_10BIT; +static bool nvenc_lossless = false; static bool nvenc_rgb; @@ -6393,64 +6405,71 @@ bool x_pv_game::ctrl() { #if BAKE_PNG || BAKE_VIDEO if (img_write && frame_prev != x_pv_game_ptr->frame) { texture* tex = rctx_ptr->screen_buffer.color_texture; - int32_t width = tex->width; - int32_t height = tex->height; + const int32_t width = tex->width; + const int32_t height = tex->height; #if BAKE_VIDEO - if (GLAD_WGL_NV_DX_interop2) { - d3d_gl_fbo_tex.lock(); + d3d_gl_fbo_tex.lock(); - gl_state_bind_framebuffer(d3d_gl_fbo_tex.fbo); - gl_state_active_bind_texture_2d(0, tex->glid); - gl_state_bind_sampler(0, rctx_ptr->render_samplers[1]); - - if (nvenc_rgb) { - GLint swizzle_rgb1[] = { GL_RED, GL_BLUE, GL_GREEN, GL_ONE }; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle_rgb1); - } - - gl_state_set_viewport(0, 0, width, height); - uniform_value[U_REDUCE] = 0; - shaders_ft.set(SHADER_FT_REDUCE); - rctx_ptr->render.draw_quad(width, height, - 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f); - - if (nvenc_rgb) { - GLint swizzle_rgba[] = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA }; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle_rgba); - } - - gl_state_bind_sampler(0, 0); - gl_state_bind_texture_2d(0); - gl_state_bind_framebuffer(0); - - d3d_gl_fbo_tex.unlock(); + gl_state_bind_framebuffer(d3d_gl_fbo_tex.fbo); + gl_state_active_bind_texture_2d(0, tex->glid); + gl_state_bind_sampler(0, rctx_ptr->render_samplers[1]); #if BAKE_VIDEO_ALPHA - d3d_gl_alpha_fbo_tex.lock(); + GLint swizzle_rgb1[] = { GL_RED, GL_GREEN, GL_BLUE, GL_ONE }; + glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle_rgb1); +#endif - gl_state_bind_framebuffer(d3d_gl_alpha_fbo_tex.fbo); - gl_state_active_bind_texture_2d(0, tex->tex); + gl_state_set_viewport(0, 0, width, height); + if (nvenc_rgb) + shaders_dev.set(SHADER_DEV_CONVERT_RGB); + else + shaders_dev.set(SHADER_DEV_CONVERT_YCBCR_BT709); + rctx_ptr->render.draw_quad(width, height, + 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f); +#if BAKE_VIDEO_ALPHA + GLint swizzle_rgba[] = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA }; + glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle_rgba); +#endif + + gl_state_bind_sampler(0, 0); + gl_state_bind_texture_2d(0); + gl_state_bind_framebuffer(0); + + d3d_gl_fbo_tex.unlock(); + +#if BAKE_VIDEO_ALPHA + d3d_gl_alpha_fbo_tex.lock(); + + gl_state_bind_framebuffer(d3d_gl_alpha_fbo_tex.fbo); + gl_state_active_bind_texture_2d(0, tex->glid); + + if (nvenc_rgb) { GLint swizzle_aaa1[] = { GL_ALPHA, GL_ALPHA, GL_ALPHA, GL_ONE }; glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle_aaa1); + } - gl_state_set_viewport(0, 0, width, height); + gl_state_set_viewport(0, 0, width, height); + if (nvenc_rgb) { uniform_value[U_REDUCE] = 0; shaders_ft.set(SHADER_FT_REDUCE); - rctx_ptr->render.draw_quad(width, height, - 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f); + } + else + shaders_dev.set(SHADER_DEV_CONVERT_ALPHA); + rctx_ptr->render.draw_quad(width, height, + 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f); - GLint swizzle_rgba[] = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA }; + if (nvenc_rgb) glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle_rgba); - gl_state_bind_texture_2d(0); - gl_state_bind_framebuffer(0); + gl_state_bind_texture_2d(0); + gl_state_bind_framebuffer(0); - d3d_gl_alpha_fbo_tex.unlock(); - #endif - } - else { + d3d_gl_alpha_fbo_tex.unlock(); +#endif + + if (!GLAD_WGL_NV_DX_interop2) { void (*conv_func)(uint8_t * src, uint8_t * dst); conv_func = [](uint8_t* src, uint8_t* dst) { @@ -6458,71 +6477,10 @@ bool x_pv_game::ctrl() { *(uint32_t*)dst = (temp & 0xFFFFFF) | (0xFF << 24); }; - if (nvenc_rgb) { - conv_func = [](uint8_t* src, uint8_t* dst) { - const uint32_t temp = *(uint32_t*)src; - *(uint32_t*)dst = (temp & 0xFF) | ((temp & 0xFF00) << 8) - | ((temp & 0xFF0000) >> 8) | (0xFF << 24); - }; - } - -#if BAKE_VIDEO_ALPHA - void (*conv_func_alpha)(uint8_t * src, uint8_t * dst); - - conv_func_alpha = [](uint8_t* src, uint8_t* dst) { - const uint32_t temp = *(uint32_t*)src; - const uint32_t alpha = (temp >> 24) & 0xFF; - *(uint32_t*)dst = alpha | (alpha << 8) | (alpha << 16) | (0xFF << 24); - }; - - if (nvenc_rgb) { - conv_func_alpha = [](uint8_t* src, uint8_t* dst) { - const uint32_t temp = *(uint32_t*)src; - const uint32_t alpha = (temp >> 24) & 0xFF; - *(uint32_t*)dst = alpha | (alpha << 8) | (alpha << 16) | (0xFF << 24); - }; - } - D3D11_MAPPED_SUBRESOURCE mapped_res = {}; - HRESULT result = d3d_device_context->Map(d3d_texture, - 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_res); - D3D11_MAPPED_SUBRESOURCE mapped_alpha_res = {}; - HRESULT result_alpha = d3d_device_context->Map(d3d_alpha_texture, - 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_alpha_res); - if (SUCCEEDED(result) && SUCCEEDED(result_alpha)) { - gl_state_bind_texture_2d(tex->tex); - glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_HALF_FLOAT, nvenc_temp_pixels.data()); - gl_state_bind_texture_2d(0); - - uint8_t* src = (uint8_t*)nvenc_temp_pixels.data(); - uint8_t* dst = (uint8_t*)mapped_res.pData; - uint8_t* dst_alpha = (uint8_t*)mapped_alpha_res.pData; - - for (size_t y = 0, i = height; i; y++, i--) { - uint8_t* src1 = &src[y * width * nvenc_src_pixel_size]; - uint8_t* dst1 = &dst[(height - y - 1) * width * nvenc_dst_pixel_size]; - uint8_t* dst1_alpha = &dst_alpha[(height - y - 1) * width * nvenc_dst_pixel_size]; - - for (size_t x = 0, j = width; j; x++, j--, src1 += nvenc_src_pixel_size, - dst1 += nvenc_dst_pixel_size, dst1_alpha += nvenc_dst_pixel_size) { - conv_func(src1, dst1); - conv_func_alpha(src1, dst1_alpha); - } - } - - d3d_device_context->Unmap(d3d_texture, 0); - d3d_device_context->Unmap(d3d_alpha_texture, 0); - } - else { - if (SUCCEEDED(result)) - d3d_device_context->Unmap(d3d_texture, 0); - if (SUCCEEDED(result_alpha)) - d3d_device_context->Unmap(d3d_alpha_texture, 0); - } -#else - D3D11_MAPPED_SUBRESOURCE mapped_res = {}; - if (SUCCEEDED(d3d_device_context->Map(d3d_texture, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_res))) { - gl_state_bind_texture_2d(tex->glid); + if (SUCCEEDED(d3d_device_context->Map(d3d_texture, + 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_res))) { + gl_state_bind_texture_2d(d3d_gl_fbo_tex.tex); glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, nvenc_temp_pixels.data()); gl_state_bind_texture_2d(0); @@ -6540,6 +6498,29 @@ bool x_pv_game::ctrl() { d3d_device_context->Unmap(d3d_texture, 0); } + +#if BAKE_VIDEO_ALPHA + D3D11_MAPPED_SUBRESOURCE mapped_alpha_res = {}; + if (SUCCEEDED(d3d_device_context->Map(d3d_alpha_texture, + 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_alpha_res))) { + gl_state_bind_texture_2d(d3d_gl_alpha_fbo_tex.tex); + glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, nvenc_temp_pixels.data()); + gl_state_bind_texture_2d(0); + + uint8_t* src = (uint8_t*)nvenc_temp_pixels.data(); + uint8_t* dst = (uint8_t*)mapped_alpha_res.pData; + + for (size_t y = 0, i = height; i; y++, i--) { + uint8_t* src1 = &src[y * width * nvenc_src_pixel_size]; + uint8_t* dst1 = &dst[(height - y - 1) * width * nvenc_dst_pixel_size]; + + for (size_t x = 0, j = width; j; x++, j--, + src1 += nvenc_src_pixel_size, dst1 += nvenc_dst_pixel_size) + conv_func(src1, dst1); + } + + d3d_device_context->Unmap(d3d_alpha_texture, 0); + } #endif } @@ -7899,8 +7880,7 @@ bool x_pv_game::ctrl() { const int32_t height = BAKE_BASE_HEIGHT * BAKE_RES_SCALE; #if BAKE_VIDEO - nvenc_rgb = (nvenc_format == NVENC_ENCODER_RGB - || nvenc_format == NVENC_ENCODER_RGB_10BIT); + nvenc_rgb = nvenc_format == NVENC_ENCODER_RGB || nvenc_format == NVENC_ENCODER_RGB_10BIT; { D3D11_TEXTURE2D_DESC tex_desc = {}; @@ -7908,7 +7888,7 @@ bool x_pv_game::ctrl() { tex_desc.Height = height; tex_desc.MipLevels = 1; tex_desc.ArraySize = 1; - tex_desc.Format = nvenc_rgb ? DXGI_FORMAT_AYUV : DXGI_FORMAT_R8G8B8A8_UNORM; + tex_desc.Format = DXGI_FORMAT_AYUV; tex_desc.SampleDesc.Count = 1; tex_desc.SampleDesc.Quality = 0; if (GLAD_WGL_NV_DX_interop2) { @@ -7929,12 +7909,10 @@ bool x_pv_game::ctrl() { #endif } - if (GLAD_WGL_NV_DX_interop2) { - d3d_gl_fbo_tex.init(d3d_texture); + d3d_gl_fbo_tex.init(d3d_texture); #if BAKE_VIDEO_ALPHA - d3d_gl_alpha_fbo_tex.init(d3d_alpha_texture); + d3d_gl_alpha_fbo_tex.init(d3d_alpha_texture); #endif - } if (!GLAD_WGL_NV_DX_interop2) nvenc_temp_pixels.resize((size_t)width * (size_t)height * nvenc_src_pixel_size); @@ -8035,12 +8013,10 @@ bool x_pv_game::ctrl() { delete nvenc_enc; nvenc_enc = 0; - if (GLAD_WGL_NV_DX_interop2) { #if BAKE_VIDEO_ALPHA - d3d_gl_alpha_fbo_tex.free(); + d3d_gl_alpha_fbo_tex.free(); #endif - d3d_gl_fbo_tex.free(); - } + d3d_gl_fbo_tex.free(); #if BAKE_VIDEO_ALPHA d3d_alpha_texture->Release(); @@ -10261,10 +10237,6 @@ XPVGameSelector::~XPVGameSelector() { bool XPVGameSelector::init() { start = false; exit = false; -#if BAKE_VIDEO - nvenc_format = NVENC_ENCODER_YUV420_10BIT; - nvenc_lossless = false; -#endif return true; } @@ -10469,6 +10441,20 @@ void XPVGameSelector::window() { }; ImGui::ColumnComboBox("Format", nvenc_format_names, 6, (int32_t*)&nvenc_format, 0, false, &focus); + + switch (nvenc_format) { + case NVENC_ENCODER_YUV420: + case NVENC_ENCODER_YUV444: + case NVENC_ENCODER_RGB: + ImGui::Checkbox("Lossless", &nvenc_lossless); + break; + case NVENC_ENCODER_YUV420_10BIT: + case NVENC_ENCODER_YUV444_10BIT: + case NVENC_ENCODER_RGB_10BIT: + ImGui::Checkbox("Lossless (Will be saved at 8 bits!)", &nvenc_lossless); + break; + } + ImGui::Checkbox("Lossless", &nvenc_lossless); ImGui::EndChild(); }