mirror of
https://github.com/obsproject/obs-studio.git
synced 2024-09-19 20:32:15 +02:00
libobs,libobs-opengl: enable GPU encoding for OpenGL
Enable all of the previously Windows only paths for OpenGL backends that support encode_texture2 Co-authored-by: Torge Matthies <openglfreak@googlemail.com>
This commit is contained in:
parent
f81ed52ec7
commit
02c90207fc
@ -1519,6 +1519,18 @@ void gs_swapchain_destroy(gs_swapchain_t *swapchain)
|
||||
bfree(swapchain);
|
||||
}
|
||||
|
||||
bool device_nv12_available(gs_device_t *device)
|
||||
{
|
||||
UNUSED_PARAMETER(device);
|
||||
return true; // always a split R8,R8G8 texture.
|
||||
}
|
||||
|
||||
bool device_p010_available(gs_device_t *device)
|
||||
{
|
||||
UNUSED_PARAMETER(device);
|
||||
return true; // always a split R16,R16G16 texture.
|
||||
}
|
||||
|
||||
uint32_t gs_voltexture_get_width(const gs_texture_t *voltex)
|
||||
{
|
||||
/* TODO */
|
||||
|
@ -195,6 +195,8 @@ bool load_graphics_imports(struct gs_exports *exports, void *module,
|
||||
|
||||
GRAPHICS_IMPORT_OPTIONAL(device_nv12_available);
|
||||
GRAPHICS_IMPORT_OPTIONAL(device_p010_available);
|
||||
GRAPHICS_IMPORT_OPTIONAL(device_texture_create_nv12);
|
||||
GRAPHICS_IMPORT_OPTIONAL(device_texture_create_p010);
|
||||
|
||||
GRAPHICS_IMPORT(device_is_monitor_hdr);
|
||||
|
||||
@ -231,8 +233,6 @@ bool load_graphics_imports(struct gs_exports *exports, void *module,
|
||||
GRAPHICS_IMPORT_OPTIONAL(device_texture_wrap_obj);
|
||||
GRAPHICS_IMPORT_OPTIONAL(device_texture_acquire_sync);
|
||||
GRAPHICS_IMPORT_OPTIONAL(device_texture_release_sync);
|
||||
GRAPHICS_IMPORT_OPTIONAL(device_texture_create_nv12);
|
||||
GRAPHICS_IMPORT_OPTIONAL(device_texture_create_p010);
|
||||
GRAPHICS_IMPORT_OPTIONAL(device_stagesurface_create_nv12);
|
||||
GRAPHICS_IMPORT_OPTIONAL(device_stagesurface_create_p010);
|
||||
GRAPHICS_IMPORT_OPTIONAL(device_register_loss_callbacks);
|
||||
|
@ -273,6 +273,16 @@ struct gs_exports {
|
||||
|
||||
bool (*device_nv12_available)(gs_device_t *device);
|
||||
bool (*device_p010_available)(gs_device_t *device);
|
||||
bool (*device_texture_create_nv12)(gs_device_t *device,
|
||||
gs_texture_t **tex_y,
|
||||
gs_texture_t **tex_uv,
|
||||
uint32_t width, uint32_t height,
|
||||
uint32_t flags);
|
||||
bool (*device_texture_create_p010)(gs_device_t *device,
|
||||
gs_texture_t **tex_y,
|
||||
gs_texture_t **tex_uv,
|
||||
uint32_t width, uint32_t height,
|
||||
uint32_t flags);
|
||||
|
||||
bool (*device_is_monitor_hdr)(gs_device_t *device, void *monitor);
|
||||
|
||||
@ -331,16 +341,6 @@ struct gs_exports {
|
||||
int (*device_texture_acquire_sync)(gs_texture_t *tex, uint64_t key,
|
||||
uint32_t ms);
|
||||
int (*device_texture_release_sync)(gs_texture_t *tex, uint64_t key);
|
||||
bool (*device_texture_create_nv12)(gs_device_t *device,
|
||||
gs_texture_t **tex_y,
|
||||
gs_texture_t **tex_uv,
|
||||
uint32_t width, uint32_t height,
|
||||
uint32_t flags);
|
||||
bool (*device_texture_create_p010)(gs_device_t *device,
|
||||
gs_texture_t **tex_y,
|
||||
gs_texture_t **tex_uv,
|
||||
uint32_t width, uint32_t height,
|
||||
uint32_t flags);
|
||||
|
||||
gs_stagesurf_t *(*device_stagesurface_create_nv12)(gs_device_t *device,
|
||||
uint32_t width,
|
||||
|
@ -2908,6 +2908,84 @@ void gs_debug_marker_end(void)
|
||||
thread_graphics->device);
|
||||
}
|
||||
|
||||
bool gs_texture_create_nv12(gs_texture_t **tex_y, gs_texture_t **tex_uv,
|
||||
uint32_t width, uint32_t height, uint32_t flags)
|
||||
{
|
||||
graphics_t *graphics = thread_graphics;
|
||||
bool success = false;
|
||||
|
||||
if (!gs_valid("gs_texture_create_nv12"))
|
||||
return false;
|
||||
|
||||
if ((width & 1) == 1 || (height & 1) == 1) {
|
||||
blog(LOG_ERROR, "NV12 textures must have dimensions "
|
||||
"divisible by 2.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (graphics->exports.device_texture_create_nv12) {
|
||||
success = graphics->exports.device_texture_create_nv12(
|
||||
graphics->device, tex_y, tex_uv, width, height, flags);
|
||||
if (success)
|
||||
return true;
|
||||
}
|
||||
|
||||
*tex_y = gs_texture_create(width, height, GS_R8, 1, NULL, flags);
|
||||
*tex_uv = gs_texture_create(width / 2, height / 2, GS_R8G8, 1, NULL,
|
||||
flags);
|
||||
|
||||
if (!*tex_y || !*tex_uv) {
|
||||
if (*tex_y)
|
||||
gs_texture_destroy(*tex_y);
|
||||
if (*tex_uv)
|
||||
gs_texture_destroy(*tex_uv);
|
||||
*tex_y = NULL;
|
||||
*tex_uv = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool gs_texture_create_p010(gs_texture_t **tex_y, gs_texture_t **tex_uv,
|
||||
uint32_t width, uint32_t height, uint32_t flags)
|
||||
{
|
||||
graphics_t *graphics = thread_graphics;
|
||||
bool success = false;
|
||||
|
||||
if (!gs_valid("gs_texture_create_p010"))
|
||||
return false;
|
||||
|
||||
if ((width & 1) == 1 || (height & 1) == 1) {
|
||||
blog(LOG_ERROR, "P010 textures must have dimensions "
|
||||
"divisible by 2.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (graphics->exports.device_texture_create_p010) {
|
||||
success = graphics->exports.device_texture_create_p010(
|
||||
graphics->device, tex_y, tex_uv, width, height, flags);
|
||||
if (success)
|
||||
return true;
|
||||
}
|
||||
|
||||
*tex_y = gs_texture_create(width, height, GS_R16, 1, NULL, flags);
|
||||
*tex_uv = gs_texture_create(width / 2, height / 2, GS_RG16, 1, NULL,
|
||||
flags);
|
||||
|
||||
if (!*tex_y || !*tex_uv) {
|
||||
if (*tex_y)
|
||||
gs_texture_destroy(*tex_y);
|
||||
if (*tex_uv)
|
||||
gs_texture_destroy(*tex_uv);
|
||||
*tex_y = NULL;
|
||||
*tex_uv = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
/** Platform specific functions */
|
||||
@ -3186,84 +3264,6 @@ int gs_texture_release_sync(gs_texture_t *tex, uint64_t key)
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool gs_texture_create_nv12(gs_texture_t **tex_y, gs_texture_t **tex_uv,
|
||||
uint32_t width, uint32_t height, uint32_t flags)
|
||||
{
|
||||
graphics_t *graphics = thread_graphics;
|
||||
bool success = false;
|
||||
|
||||
if (!gs_valid("gs_texture_create_nv12"))
|
||||
return false;
|
||||
|
||||
if ((width & 1) == 1 || (height & 1) == 1) {
|
||||
blog(LOG_ERROR, "NV12 textures must have dimensions "
|
||||
"divisible by 2.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (graphics->exports.device_texture_create_nv12) {
|
||||
success = graphics->exports.device_texture_create_nv12(
|
||||
graphics->device, tex_y, tex_uv, width, height, flags);
|
||||
if (success)
|
||||
return true;
|
||||
}
|
||||
|
||||
*tex_y = gs_texture_create(width, height, GS_R8, 1, NULL, flags);
|
||||
*tex_uv = gs_texture_create(width / 2, height / 2, GS_R8G8, 1, NULL,
|
||||
flags);
|
||||
|
||||
if (!*tex_y || !*tex_uv) {
|
||||
if (*tex_y)
|
||||
gs_texture_destroy(*tex_y);
|
||||
if (*tex_uv)
|
||||
gs_texture_destroy(*tex_uv);
|
||||
*tex_y = NULL;
|
||||
*tex_uv = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool gs_texture_create_p010(gs_texture_t **tex_y, gs_texture_t **tex_uv,
|
||||
uint32_t width, uint32_t height, uint32_t flags)
|
||||
{
|
||||
graphics_t *graphics = thread_graphics;
|
||||
bool success = false;
|
||||
|
||||
if (!gs_valid("gs_texture_create_p010"))
|
||||
return false;
|
||||
|
||||
if ((width & 1) == 1 || (height & 1) == 1) {
|
||||
blog(LOG_ERROR, "P010 textures must have dimensions "
|
||||
"divisible by 2.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (graphics->exports.device_texture_create_p010) {
|
||||
success = graphics->exports.device_texture_create_p010(
|
||||
graphics->device, tex_y, tex_uv, width, height, flags);
|
||||
if (success)
|
||||
return true;
|
||||
}
|
||||
|
||||
*tex_y = gs_texture_create(width, height, GS_R16, 1, NULL, flags);
|
||||
*tex_uv = gs_texture_create(width / 2, height / 2, GS_RG16, 1, NULL,
|
||||
flags);
|
||||
|
||||
if (!*tex_y || !*tex_uv) {
|
||||
if (*tex_y)
|
||||
gs_texture_destroy(*tex_y);
|
||||
if (*tex_uv)
|
||||
gs_texture_destroy(*tex_uv);
|
||||
*tex_y = NULL;
|
||||
*tex_uv = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
gs_stagesurf_t *gs_stagesurface_create_nv12(uint32_t width, uint32_t height)
|
||||
{
|
||||
graphics_t *graphics = thread_graphics;
|
||||
|
@ -857,6 +857,12 @@ EXPORT bool gs_timer_range_get_data(gs_timer_range_t *range, bool *disjoint,
|
||||
|
||||
EXPORT bool gs_nv12_available(void);
|
||||
EXPORT bool gs_p010_available(void);
|
||||
EXPORT bool gs_texture_create_nv12(gs_texture_t **tex_y, gs_texture_t **tex_uv,
|
||||
uint32_t width, uint32_t height,
|
||||
uint32_t flags);
|
||||
EXPORT bool gs_texture_create_p010(gs_texture_t **tex_y, gs_texture_t **tex_uv,
|
||||
uint32_t width, uint32_t height,
|
||||
uint32_t flags);
|
||||
|
||||
EXPORT bool gs_is_monitor_hdr(void *monitor);
|
||||
|
||||
@ -956,13 +962,6 @@ EXPORT int gs_texture_acquire_sync(gs_texture_t *tex, uint64_t key,
|
||||
*/
|
||||
EXPORT int gs_texture_release_sync(gs_texture_t *tex, uint64_t key);
|
||||
|
||||
EXPORT bool gs_texture_create_nv12(gs_texture_t **tex_y, gs_texture_t **tex_uv,
|
||||
uint32_t width, uint32_t height,
|
||||
uint32_t flags);
|
||||
EXPORT bool gs_texture_create_p010(gs_texture_t **tex_y, gs_texture_t **tex_uv,
|
||||
uint32_t width, uint32_t height,
|
||||
uint32_t flags);
|
||||
|
||||
EXPORT gs_stagesurf_t *gs_stagesurface_create_nv12(uint32_t width,
|
||||
uint32_t height);
|
||||
EXPORT gs_stagesurf_t *gs_stagesurface_create_p010(uint32_t width,
|
||||
|
@ -29,6 +29,9 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct obs_encoder;
|
||||
typedef struct obs_encoder obs_encoder_t;
|
||||
|
||||
#define OBS_ENCODER_CAP_DEPRECATED (1 << 0)
|
||||
#define OBS_ENCODER_CAP_PASS_TEXTURE (1 << 1)
|
||||
#define OBS_ENCODER_CAP_DYN_BITRATE (1 << 2)
|
||||
|
@ -269,9 +269,9 @@ struct obs_core_video_mix {
|
||||
gs_stagesurf_t *active_copy_surfaces[NUM_TEXTURES][NUM_CHANNELS];
|
||||
gs_stagesurf_t *copy_surfaces[NUM_TEXTURES][NUM_CHANNELS];
|
||||
gs_texture_t *convert_textures[NUM_CHANNELS];
|
||||
gs_texture_t *convert_textures_encode[NUM_CHANNELS];
|
||||
#ifdef _WIN32
|
||||
gs_stagesurf_t *copy_surfaces_encode[NUM_TEXTURES];
|
||||
gs_texture_t *convert_textures_encode[NUM_CHANNELS];
|
||||
#endif
|
||||
gs_texture_t *render_texture;
|
||||
gs_texture_t *output_texture;
|
||||
|
@ -17,8 +17,11 @@
|
||||
|
||||
#include "obs-internal.h"
|
||||
|
||||
static void *gpu_encode_thread(struct obs_core_video_mix *video)
|
||||
#define NBSP "\xC2\xA0"
|
||||
static const char *gpu_encode_frame_name = "gpu_encode_frame";
|
||||
static void *gpu_encode_thread(void *data)
|
||||
{
|
||||
struct obs_core_video_mix *video = data;
|
||||
uint64_t interval = video_output_get_frame_time(video->video);
|
||||
DARRAY(obs_encoder_t *) encoders;
|
||||
int wait_frames = NUM_ENCODE_TEXTURE_FRAMES_TO_WAIT;
|
||||
@ -26,6 +29,10 @@ static void *gpu_encode_thread(struct obs_core_video_mix *video)
|
||||
da_init(encoders);
|
||||
|
||||
os_set_thread_name("obs gpu encode thread");
|
||||
const char *gpu_encode_thread_name = profile_store_name(
|
||||
obs_get_profiler_name_store(),
|
||||
"obs_gpu_encode_thread(%g" NBSP "ms)", interval / 1000000.);
|
||||
profile_register_root(gpu_encode_thread_name, interval);
|
||||
|
||||
while (os_sem_wait(video->gpu_encode_semaphore) == 0) {
|
||||
struct obs_tex_frame tf;
|
||||
@ -42,6 +49,8 @@ static void *gpu_encode_thread(struct obs_core_video_mix *video)
|
||||
continue;
|
||||
}
|
||||
|
||||
profile_start(gpu_encode_thread_name);
|
||||
|
||||
os_event_reset(video->gpu_encode_inactive);
|
||||
|
||||
/* -------------- */
|
||||
@ -125,6 +134,7 @@ static void *gpu_encode_thread(struct obs_core_video_mix *video)
|
||||
else
|
||||
next_key++;
|
||||
|
||||
profile_start(gpu_encode_frame_name);
|
||||
if (encoder->info.encode_texture2) {
|
||||
struct encoder_texture tex = {0};
|
||||
|
||||
@ -142,6 +152,8 @@ static void *gpu_encode_thread(struct obs_core_video_mix *video)
|
||||
encoder->cur_pts, lock_key, &next_key,
|
||||
&pkt, &received);
|
||||
}
|
||||
profile_end(gpu_encode_frame_name);
|
||||
|
||||
send_off_encoder_packet(encoder, success, received,
|
||||
&pkt);
|
||||
|
||||
@ -178,6 +190,9 @@ static void *gpu_encode_thread(struct obs_core_video_mix *video)
|
||||
obs_encoder_release(encoders.array[i]);
|
||||
|
||||
da_resize(encoders, 0);
|
||||
|
||||
profile_end(gpu_encode_thread_name);
|
||||
profile_reenable_thread();
|
||||
}
|
||||
|
||||
da_free(encoders);
|
||||
@ -186,7 +201,6 @@ static void *gpu_encode_thread(struct obs_core_video_mix *video)
|
||||
|
||||
bool init_gpu_encoding(struct obs_core_video_mix *video)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
const struct video_output_info *info =
|
||||
video_output_get_info(video->video);
|
||||
|
||||
@ -210,7 +224,11 @@ bool init_gpu_encoding(struct obs_core_video_mix *video)
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
uint32_t handle = gs_texture_get_shared_handle(tex);
|
||||
#else
|
||||
uint32_t handle = (uint32_t)-1;
|
||||
#endif
|
||||
|
||||
struct obs_tex_frame frame = {.tex = tex,
|
||||
.tex_uv = tex_uv,
|
||||
@ -233,10 +251,6 @@ bool init_gpu_encoding(struct obs_core_video_mix *video)
|
||||
|
||||
video->gpu_encode_thread_initialized = true;
|
||||
return true;
|
||||
#else
|
||||
UNUSED_PARAMETER(video);
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void stop_gpu_encoding_thread(struct obs_core_video_mix *video)
|
||||
|
@ -477,7 +477,6 @@ stage_output_texture(struct obs_core_video_mix *video, int cur_texture,
|
||||
profile_end(stage_output_texture_name);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
static inline bool queue_frame(struct obs_core_video_mix *video,
|
||||
bool raw_active,
|
||||
struct obs_vframe_info *vframe_info)
|
||||
@ -505,7 +504,9 @@ static inline bool queue_frame(struct obs_core_video_mix *video,
|
||||
deque_pop_front(&video->gpu_encoder_avail_queue, &tf, sizeof(tf));
|
||||
|
||||
if (tf.released) {
|
||||
#ifdef _WIN32
|
||||
gs_texture_acquire_sync(tf.tex, tf.lock_key, GS_WAIT_INFINITE);
|
||||
#endif
|
||||
tf.released = false;
|
||||
}
|
||||
|
||||
@ -529,8 +530,10 @@ static inline bool queue_frame(struct obs_core_video_mix *video,
|
||||
tf.count = 1;
|
||||
tf.timestamp = vframe_info->timestamp;
|
||||
tf.released = true;
|
||||
#ifdef _WIN32
|
||||
tf.handle = gs_texture_get_shared_handle(tf.tex);
|
||||
gs_texture_release_sync(tf.tex, ++tf.lock_key);
|
||||
#endif
|
||||
deque_push_back(&video->gpu_encoder_queue, &tf, sizeof(tf));
|
||||
|
||||
os_sem_post(video->gpu_encode_semaphore);
|
||||
@ -570,7 +573,6 @@ static void output_gpu_encoders(struct obs_core_video_mix *video,
|
||||
end:
|
||||
profile_end(output_gpu_encoders_name);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void render_video(struct obs_core_video_mix *video,
|
||||
bool raw_active, const bool gpu_active,
|
||||
@ -590,26 +592,24 @@ static inline void render_video(struct obs_core_video_mix *video,
|
||||
size_t channel_count = NUM_CHANNELS;
|
||||
gs_texture_t *output_texture = render_output_texture(video);
|
||||
|
||||
#ifdef _WIN32
|
||||
if (gpu_active) {
|
||||
convert_textures = video->convert_textures_encode;
|
||||
#ifdef _WIN32
|
||||
copy_surfaces = video->copy_surfaces_encode;
|
||||
channel_count = 1;
|
||||
#endif
|
||||
gs_flush();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (video->gpu_conversion) {
|
||||
render_convert_texture(video, convert_textures,
|
||||
output_texture);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (gpu_active) {
|
||||
gs_flush();
|
||||
output_gpu_encoders(video, raw_active);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (raw_active) {
|
||||
stage_output_texture(video, cur_texture,
|
||||
@ -1014,12 +1014,10 @@ static void clear_raw_frame_data(struct obs_core_video_mix *video)
|
||||
deque_free(&video->vframe_info_buffer);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
static void clear_gpu_frame_data(struct obs_core_video_mix *video)
|
||||
{
|
||||
deque_free(&video->vframe_info_buffer_gpu);
|
||||
}
|
||||
#endif
|
||||
|
||||
extern THREAD_LOCAL bool is_graphics_thread;
|
||||
|
||||
@ -1127,30 +1125,22 @@ static const char *output_frame_name = "output_frame";
|
||||
static inline void update_active_state(struct obs_core_video_mix *video)
|
||||
{
|
||||
const bool raw_was_active = video->raw_was_active;
|
||||
#ifdef _WIN32
|
||||
const bool gpu_was_active = video->gpu_was_active;
|
||||
#endif
|
||||
const bool was_active = video->was_active;
|
||||
|
||||
bool raw_active = os_atomic_load_long(&video->raw_active) > 0;
|
||||
#ifdef _WIN32
|
||||
const bool gpu_active =
|
||||
os_atomic_load_long(&video->gpu_encoder_active) > 0;
|
||||
const bool active = raw_active || gpu_active;
|
||||
#else
|
||||
const bool active = raw_active;
|
||||
#endif
|
||||
|
||||
if (!was_active && active)
|
||||
clear_base_frame_data(video);
|
||||
if (!raw_was_active && raw_active)
|
||||
clear_raw_frame_data(video);
|
||||
#ifdef _WIN32
|
||||
if (!gpu_was_active && gpu_active)
|
||||
clear_gpu_frame_data(video);
|
||||
|
||||
video->gpu_was_active = gpu_active;
|
||||
#endif
|
||||
video->raw_was_active = raw_active;
|
||||
video->was_active = active;
|
||||
}
|
||||
|
@ -179,7 +179,6 @@ static bool obs_init_gpu_conversion(struct obs_core_video_mix *video)
|
||||
video->convert_textures[0] = NULL;
|
||||
video->convert_textures[1] = NULL;
|
||||
video->convert_textures[2] = NULL;
|
||||
#ifdef _WIN32
|
||||
video->convert_textures_encode[0] = NULL;
|
||||
video->convert_textures_encode[1] = NULL;
|
||||
video->convert_textures_encode[2] = NULL;
|
||||
@ -200,7 +199,6 @@ static bool obs_init_gpu_conversion(struct obs_core_video_mix *video)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool success = true;
|
||||
|
||||
@ -297,13 +295,11 @@ static bool obs_init_gpu_conversion(struct obs_core_video_mix *video)
|
||||
gs_texture_destroy(video->convert_textures[c]);
|
||||
video->convert_textures[c] = NULL;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
if (video->convert_textures_encode[c]) {
|
||||
gs_texture_destroy(
|
||||
video->convert_textures_encode[c]);
|
||||
video->convert_textures_encode[c] = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -830,12 +826,10 @@ static void obs_free_render_textures(struct obs_core_video_mix *video)
|
||||
gs_texture_destroy(video->convert_textures[c]);
|
||||
video->convert_textures[c] = NULL;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
if (video->convert_textures_encode[c]) {
|
||||
gs_texture_destroy(video->convert_textures_encode[c]);
|
||||
video->convert_textures_encode[c] = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
gs_texture_destroy(video->output_texture);
|
||||
|
Loading…
Reference in New Issue
Block a user