diff options
Diffstat (limited to 'src/encoder/video')
-rw-r--r-- | src/encoder/video/nvenc.c (renamed from src/encoder/video/cuda.c) | 102 | ||||
-rw-r--r-- | src/encoder/video/software.c | 35 | ||||
-rw-r--r-- | src/encoder/video/vaapi.c | 19 | ||||
-rw-r--r-- | src/encoder/video/video.c | 16 | ||||
-rw-r--r-- | src/encoder/video/vulkan.c | 187 |
5 files changed, 269 insertions, 90 deletions
diff --git a/src/encoder/video/cuda.c b/src/encoder/video/nvenc.c index f3cc9a4..5f578c2 100644 --- a/src/encoder/video/cuda.c +++ b/src/encoder/video/nvenc.c @@ -1,6 +1,7 @@ -#include "../../../include/encoder/video/cuda.h" +#include "../../../include/encoder/video/nvenc.h" #include "../../../include/egl.h" #include "../../../include/cuda.h" +#include "../../../include/window/window.h" #include <libavcodec/avcodec.h> #include <libavutil/hwcontext_cuda.h> @@ -8,7 +9,7 @@ #include <stdlib.h> typedef struct { - gsr_video_encoder_cuda_params params; + gsr_video_encoder_nvenc_params params; unsigned int target_textures[2]; @@ -18,12 +19,12 @@ typedef struct { CUgraphicsResource cuda_graphics_resources[2]; CUarray mapped_arrays[2]; CUstream cuda_stream; -} gsr_video_encoder_cuda; +} gsr_video_encoder_nvenc; -static bool gsr_video_encoder_cuda_setup_context(gsr_video_encoder_cuda *self, AVCodecContext *video_codec_context) { +static bool gsr_video_encoder_nvenc_setup_context(gsr_video_encoder_nvenc *self, AVCodecContext *video_codec_context) { self->device_ctx = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_CUDA); if(!self->device_ctx) { - fprintf(stderr, "gsr error: gsr_video_encoder_cuda_setup_context failed: failed to create hardware device context\n"); + fprintf(stderr, "gsr error: gsr_video_encoder_nvenc_setup_context failed: failed to create hardware device context\n"); return false; } @@ -31,14 +32,14 @@ static bool gsr_video_encoder_cuda_setup_context(gsr_video_encoder_cuda *self, A AVCUDADeviceContext *cuda_device_context = (AVCUDADeviceContext*)hw_device_context->hwctx; cuda_device_context->cuda_ctx = self->cuda.cu_ctx; if(av_hwdevice_ctx_init(self->device_ctx) < 0) { - fprintf(stderr, "gsr error: gsr_video_encoder_cuda_setup_context failed: failed to create hardware device context\n"); + fprintf(stderr, "gsr error: gsr_video_encoder_nvenc_setup_context failed: failed to create hardware device context\n"); av_buffer_unref(&self->device_ctx); return false; } AVBufferRef *frame_context = av_hwframe_ctx_alloc(self->device_ctx); if(!frame_context) { - fprintf(stderr, "gsr error: gsr_video_encoder_cuda_setup_context failed: failed to create hwframe context\n"); + fprintf(stderr, "gsr error: gsr_video_encoder_nvenc_setup_context failed: failed to create hwframe context\n"); av_buffer_unref(&self->device_ctx); return false; } @@ -51,7 +52,7 @@ static bool gsr_video_encoder_cuda_setup_context(gsr_video_encoder_cuda *self, A hw_frame_context->device_ctx = (AVHWDeviceContext*)self->device_ctx->data; if (av_hwframe_ctx_init(frame_context) < 0) { - fprintf(stderr, "gsr error: gsr_video_encoder_cuda_setup_context failed: failed to initialize hardware frame context " + fprintf(stderr, "gsr error: gsr_video_encoder_nvenc_setup_context failed: failed to initialize hardware frame context " "(note: ffmpeg version needs to be > 4.0)\n"); av_buffer_unref(&self->device_ctx); //av_buffer_unref(&frame_context); @@ -64,21 +65,6 @@ static bool gsr_video_encoder_cuda_setup_context(gsr_video_encoder_cuda *self, A return true; } -static unsigned int gl_create_texture(gsr_egl *egl, int width, int height, int internal_format, unsigned int format) { - unsigned int texture_id = 0; - egl->glGenTextures(1, &texture_id); - egl->glBindTexture(GL_TEXTURE_2D, texture_id); - egl->glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, format, GL_UNSIGNED_BYTE, NULL); - - egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - egl->glBindTexture(GL_TEXTURE_2D, 0); - return texture_id; -} - static bool cuda_register_opengl_texture(gsr_cuda *cuda, CUgraphicsResource *cuda_graphics_resource, CUarray *mapped_array, unsigned int texture_id) { CUresult res; res = cuda->cuGraphicsGLRegisterImage(cuda_graphics_resource, texture_id, GL_TEXTURE_2D, CU_GRAPHICS_REGISTER_FLAGS_NONE); @@ -96,10 +82,10 @@ static bool cuda_register_opengl_texture(gsr_cuda *cuda, CUgraphicsResource *cud return true; } -static bool gsr_video_encoder_cuda_setup_textures(gsr_video_encoder_cuda *self, AVCodecContext *video_codec_context, AVFrame *frame) { +static bool gsr_video_encoder_nvenc_setup_textures(gsr_video_encoder_nvenc *self, AVCodecContext *video_codec_context, AVFrame *frame) { const int res = av_hwframe_get_buffer(video_codec_context->hw_frames_ctx, frame, 0); if(res < 0) { - fprintf(stderr, "gsr error: gsr_video_encoder_cuda_setup_textures: av_hwframe_get_buffer failed: %d\n", res); + fprintf(stderr, "gsr error: gsr_video_encoder_nvenc_setup_textures: av_hwframe_get_buffer failed: %d\n", res); return false; } @@ -109,9 +95,9 @@ static bool gsr_video_encoder_cuda_setup_textures(gsr_video_encoder_cuda *self, const int div[2] = {1, 2}; // divide UV texture size by 2 because chroma is half size for(int i = 0; i < 2; ++i) { - self->target_textures[i] = gl_create_texture(self->params.egl, video_codec_context->width / div[i], video_codec_context->height / div[i], self->params.color_depth == GSR_COLOR_DEPTH_8_BITS ? internal_formats_nv12[i] : internal_formats_p010[i], formats[i]); + self->target_textures[i] = gl_create_texture(self->params.egl, video_codec_context->width / div[i], video_codec_context->height / div[i], self->params.color_depth == GSR_COLOR_DEPTH_8_BITS ? internal_formats_nv12[i] : internal_formats_p010[i], formats[i], GL_NEAREST); if(self->target_textures[i] == 0) { - fprintf(stderr, "gsr error: gsr_video_encoder_cuda_setup_textures: failed to create opengl texture\n"); + fprintf(stderr, "gsr error: gsr_video_encoder_nvenc_setup_textures: failed to create opengl texture\n"); return false; } @@ -123,32 +109,46 @@ static bool gsr_video_encoder_cuda_setup_textures(gsr_video_encoder_cuda *self, return true; } -static void gsr_video_encoder_cuda_stop(gsr_video_encoder_cuda *self, AVCodecContext *video_codec_context); +static void gsr_video_encoder_nvenc_stop(gsr_video_encoder_nvenc *self, AVCodecContext *video_codec_context); -static bool gsr_video_encoder_cuda_start(gsr_video_encoder *encoder, AVCodecContext *video_codec_context, AVFrame *frame) { - gsr_video_encoder_cuda *self = encoder->priv; +static bool gsr_video_encoder_nvenc_start(gsr_video_encoder *encoder, AVCodecContext *video_codec_context, AVFrame *frame) { + gsr_video_encoder_nvenc *self = encoder->priv; - const bool overclock = gsr_egl_get_display_server(self->params.egl) == GSR_DISPLAY_SERVER_X11 ? self->params.overclock : false; - if(!gsr_cuda_load(&self->cuda, self->params.egl->x11.dpy, overclock)) { - fprintf(stderr, "gsr error: gsr_video_encoder_cuda_start: failed to load cuda\n"); - gsr_video_encoder_cuda_stop(self, video_codec_context); + const bool is_x11 = gsr_window_get_display_server(self->params.egl->window) == GSR_DISPLAY_SERVER_X11; + const bool overclock = is_x11 ? self->params.overclock : false; + Display *display = is_x11 ? gsr_window_get_display(self->params.egl->window) : NULL; + if(!gsr_cuda_load(&self->cuda, display, overclock)) { + fprintf(stderr, "gsr error: gsr_video_encoder_nvenc_start: failed to load cuda\n"); + gsr_video_encoder_nvenc_stop(self, video_codec_context); return false; } - if(!gsr_video_encoder_cuda_setup_context(self, video_codec_context)) { - gsr_video_encoder_cuda_stop(self, video_codec_context); + video_codec_context->width = FFALIGN(video_codec_context->width, 2); + video_codec_context->height = FFALIGN(video_codec_context->height, 2); + + if(video_codec_context->width < 128) + video_codec_context->width = 128; + + if(video_codec_context->height < 128) + video_codec_context->height = 128; + + frame->width = video_codec_context->width; + frame->height = video_codec_context->height; + + if(!gsr_video_encoder_nvenc_setup_context(self, video_codec_context)) { + gsr_video_encoder_nvenc_stop(self, video_codec_context); return false; } - if(!gsr_video_encoder_cuda_setup_textures(self, video_codec_context, frame)) { - gsr_video_encoder_cuda_stop(self, video_codec_context); + if(!gsr_video_encoder_nvenc_setup_textures(self, video_codec_context, frame)) { + gsr_video_encoder_nvenc_stop(self, video_codec_context); return false; } return true; } -void gsr_video_encoder_cuda_stop(gsr_video_encoder_cuda *self, AVCodecContext *video_codec_context) { +void gsr_video_encoder_nvenc_stop(gsr_video_encoder_nvenc *self, AVCodecContext *video_codec_context) { self->params.egl->glDeleteTextures(2, self->target_textures); self->target_textures[0] = 0; self->target_textures[1] = 0; @@ -171,8 +171,8 @@ void gsr_video_encoder_cuda_stop(gsr_video_encoder_cuda *self, AVCodecContext *v gsr_cuda_unload(&self->cuda); } -static void gsr_video_encoder_cuda_copy_textures_to_frame(gsr_video_encoder *encoder, AVFrame *frame) { - gsr_video_encoder_cuda *self = encoder->priv; +static void gsr_video_encoder_nvenc_copy_textures_to_frame(gsr_video_encoder *encoder, AVFrame *frame, gsr_color_conversion *color_conversion) { + gsr_video_encoder_nvenc *self = encoder->priv; const int div[2] = {1, 2}; // divide UV texture size by 2 because chroma is half size for(int i = 0; i < 2; ++i) { CUDA_MEMCPY2D memcpy_struct; @@ -198,26 +198,26 @@ static void gsr_video_encoder_cuda_copy_textures_to_frame(gsr_video_encoder *enc self->cuda.cuStreamSynchronize(self->cuda_stream); } -static void gsr_video_encoder_cuda_get_textures(gsr_video_encoder *encoder, unsigned int *textures, int *num_textures, gsr_destination_color *destination_color) { - gsr_video_encoder_cuda *self = encoder->priv; +static void gsr_video_encoder_nvenc_get_textures(gsr_video_encoder *encoder, unsigned int *textures, int *num_textures, gsr_destination_color *destination_color) { + gsr_video_encoder_nvenc *self = encoder->priv; textures[0] = self->target_textures[0]; textures[1] = self->target_textures[1]; *num_textures = 2; *destination_color = self->params.color_depth == GSR_COLOR_DEPTH_10_BITS ? GSR_DESTINATION_COLOR_P010 : GSR_DESTINATION_COLOR_NV12; } -static void gsr_video_encoder_cuda_destroy(gsr_video_encoder *encoder, AVCodecContext *video_codec_context) { - gsr_video_encoder_cuda_stop(encoder->priv, video_codec_context); +static void gsr_video_encoder_nvenc_destroy(gsr_video_encoder *encoder, AVCodecContext *video_codec_context) { + gsr_video_encoder_nvenc_stop(encoder->priv, video_codec_context); free(encoder->priv); free(encoder); } -gsr_video_encoder* gsr_video_encoder_cuda_create(const gsr_video_encoder_cuda_params *params) { +gsr_video_encoder* gsr_video_encoder_nvenc_create(const gsr_video_encoder_nvenc_params *params) { gsr_video_encoder *encoder = calloc(1, sizeof(gsr_video_encoder)); if(!encoder) return NULL; - gsr_video_encoder_cuda *encoder_cuda = calloc(1, sizeof(gsr_video_encoder_cuda)); + gsr_video_encoder_nvenc *encoder_cuda = calloc(1, sizeof(gsr_video_encoder_nvenc)); if(!encoder_cuda) { free(encoder); return NULL; @@ -226,10 +226,10 @@ gsr_video_encoder* gsr_video_encoder_cuda_create(const gsr_video_encoder_cuda_pa encoder_cuda->params = *params; *encoder = (gsr_video_encoder) { - .start = gsr_video_encoder_cuda_start, - .copy_textures_to_frame = gsr_video_encoder_cuda_copy_textures_to_frame, - .get_textures = gsr_video_encoder_cuda_get_textures, - .destroy = gsr_video_encoder_cuda_destroy, + .start = gsr_video_encoder_nvenc_start, + .copy_textures_to_frame = gsr_video_encoder_nvenc_copy_textures_to_frame, + .get_textures = gsr_video_encoder_nvenc_get_textures, + .destroy = gsr_video_encoder_nvenc_destroy, .priv = encoder_cuda }; diff --git a/src/encoder/video/software.c b/src/encoder/video/software.c index cedcc1b..d8d9828 100644 --- a/src/encoder/video/software.c +++ b/src/encoder/video/software.c @@ -1,5 +1,6 @@ #include "../../../include/encoder/video/software.h" #include "../../../include/egl.h" +#include "../../../include/utils.h" #include <libavcodec/avcodec.h> #include <libavutil/frame.h> @@ -14,21 +15,6 @@ typedef struct { unsigned int target_textures[2]; } gsr_video_encoder_software; -static unsigned int gl_create_texture(gsr_egl *egl, int width, int height, int internal_format, unsigned int format) { - unsigned int texture_id = 0; - egl->glGenTextures(1, &texture_id); - egl->glBindTexture(GL_TEXTURE_2D, texture_id); - egl->glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, format, GL_UNSIGNED_BYTE, NULL); - - egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - egl->glBindTexture(GL_TEXTURE_2D, 0); - return texture_id; -} - static bool gsr_video_encoder_software_setup_textures(gsr_video_encoder_software *self, AVCodecContext *video_codec_context, AVFrame *frame) { int res = av_frame_get_buffer(frame, LINESIZE_ALIGNMENT); if(res < 0) { @@ -48,7 +34,7 @@ static bool gsr_video_encoder_software_setup_textures(gsr_video_encoder_software const int div[2] = {1, 2}; // divide UV texture size by 2 because chroma is half size for(int i = 0; i < 2; ++i) { - self->target_textures[i] = gl_create_texture(self->params.egl, video_codec_context->width / div[i], video_codec_context->height / div[i], self->params.color_depth == GSR_COLOR_DEPTH_8_BITS ? internal_formats_nv12[i] : internal_formats_p010[i], formats[i]); + self->target_textures[i] = gl_create_texture(self->params.egl, video_codec_context->width / div[i], video_codec_context->height / div[i], self->params.color_depth == GSR_COLOR_DEPTH_8_BITS ? internal_formats_nv12[i] : internal_formats_p010[i], formats[i], GL_NEAREST); if(self->target_textures[i] == 0) { fprintf(stderr, "gsr error: gsr_capture_kms_setup_cuda_textures: failed to create opengl texture\n"); return false; @@ -84,21 +70,20 @@ void gsr_video_encoder_software_stop(gsr_video_encoder_software *self, AVCodecCo self->target_textures[1] = 0; } -static void gsr_video_encoder_software_copy_textures_to_frame(gsr_video_encoder *encoder, AVFrame *frame) { - gsr_video_encoder_software *self = encoder->priv; +static void gsr_video_encoder_software_copy_textures_to_frame(gsr_video_encoder *encoder, AVFrame *frame, gsr_color_conversion *color_conversion) { + (void)encoder; + //gsr_video_encoder_software *self = encoder->priv; // TODO: hdr support const unsigned int formats[2] = { GL_RED, GL_RG }; + const int div[2] = {1, 2}; // divide UV texture size by 2 because chroma is half size for(int i = 0; i < 2; ++i) { - self->params.egl->glBindTexture(GL_TEXTURE_2D, self->target_textures[i]); - // We could use glGetTexSubImage and then we wouldn't have to use a specific linesize (LINESIZE_ALIGNMENT) that adds padding, - // but glGetTexSubImage is only available starting from opengl 4.5. - self->params.egl->glGetTexImage(GL_TEXTURE_2D, 0, formats[i], GL_UNSIGNED_BYTE, frame->data[i]); + // TODO: Use glPixelStore? + gsr_color_conversion_read_destination_texture(color_conversion, i, 0, 0, frame->width / div[i], frame->height / div[i], formats[i], GL_UNSIGNED_BYTE, frame->data[i]); } - self->params.egl->glBindTexture(GL_TEXTURE_2D, 0); // cap_kms->kms.base.egl->eglSwapBuffers(cap_kms->kms.base.egl->egl_display, cap_kms->kms.base.egl->egl_surface); - self->params.egl->glFlush(); - self->params.egl->glFinish(); + //self->params.egl->glFlush(); + //self->params.egl->glFinish(); } static void gsr_video_encoder_software_get_textures(gsr_video_encoder *encoder, unsigned int *textures, int *num_textures, gsr_destination_color *destination_color) { diff --git a/src/encoder/video/vaapi.c b/src/encoder/video/vaapi.c index b5ccce9..0daf4d8 100644 --- a/src/encoder/video/vaapi.c +++ b/src/encoder/video/vaapi.c @@ -4,6 +4,7 @@ #include <libavcodec/avcodec.h> #include <libavutil/hwcontext_vaapi.h> +#include <libavutil/intreadwrite.h> #include <va/va_drmcommon.h> @@ -120,10 +121,8 @@ static bool gsr_video_encoder_vaapi_setup_textures(gsr_video_encoder_vaapi *self } self->params.egl->glBindTexture(GL_TEXTURE_2D, self->target_textures[i]); - self->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - self->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - self->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - self->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + self->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + self->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); while(self->params.egl->glGetError()) {} while(self->params.egl->eglGetError() != EGL_SUCCESS){} @@ -166,12 +165,21 @@ static bool gsr_video_encoder_vaapi_start(gsr_video_encoder *encoder, AVCodecCon } else { video_codec_context->height = FFALIGN(video_codec_context->height, 16); } + } else { + video_codec_context->width = FFALIGN(video_codec_context->width, 2); + video_codec_context->height = FFALIGN(video_codec_context->height, 2); } - if(video_codec_context->width != frame->width || video_codec_context->height != frame->height) { + if(FFALIGN(video_codec_context->width, 2) != FFALIGN(frame->width, 2) || FFALIGN(video_codec_context->height, 2) != FFALIGN(frame->height, 2)) { fprintf(stderr, "gsr warning: gsr_video_encoder_vaapi_start: black bars have been added to the video because of a bug in AMD drivers/hardware. Record with h264 codec instead (-k h264) to get around this issue\n"); } + if(video_codec_context->width < 128) + video_codec_context->width = 128; + + if(video_codec_context->height < 128) + video_codec_context->height = 128; + frame->width = video_codec_context->width; frame->height = video_codec_context->height; @@ -235,7 +243,6 @@ gsr_video_encoder* gsr_video_encoder_vaapi_create(const gsr_video_encoder_vaapi_ *encoder = (gsr_video_encoder) { .start = gsr_video_encoder_vaapi_start, - .copy_textures_to_frame = NULL, .get_textures = gsr_video_encoder_vaapi_get_textures, .destroy = gsr_video_encoder_vaapi_destroy, .priv = encoder_vaapi diff --git a/src/encoder/video/video.c b/src/encoder/video/video.c index 9b0def0..ce3b61b 100644 --- a/src/encoder/video/video.c +++ b/src/encoder/video/video.c @@ -1,4 +1,5 @@ #include "../../../include/encoder/video/video.h" + #include <assert.h> bool gsr_video_encoder_start(gsr_video_encoder *encoder, AVCodecContext *video_codec_context, AVFrame *frame) { @@ -9,18 +10,19 @@ bool gsr_video_encoder_start(gsr_video_encoder *encoder, AVCodecContext *video_c return res; } -void gsr_video_encoder_copy_textures_to_frame(gsr_video_encoder *encoder, AVFrame *frame) { +void gsr_video_encoder_destroy(gsr_video_encoder *encoder, AVCodecContext *video_codec_context) { assert(encoder->started); - if(encoder->copy_textures_to_frame) - encoder->copy_textures_to_frame(encoder, frame); + encoder->started = false; + encoder->destroy(encoder, video_codec_context); } -void gsr_video_encoder_get_textures(gsr_video_encoder *encoder, unsigned int *textures, int *num_textures, gsr_destination_color *destination_color) { +void gsr_video_encoder_copy_textures_to_frame(gsr_video_encoder *encoder, AVFrame *frame, gsr_color_conversion *color_conversion) { assert(encoder->started); - encoder->get_textures(encoder, textures, num_textures, destination_color); + if(encoder->copy_textures_to_frame) + encoder->copy_textures_to_frame(encoder, frame, color_conversion); } -void gsr_video_encoder_destroy(gsr_video_encoder *encoder, AVCodecContext *video_codec_context) { +void gsr_video_encoder_get_textures(gsr_video_encoder *encoder, unsigned int *textures, int *num_textures, gsr_destination_color *destination_color) { assert(encoder->started); - encoder->destroy(encoder, video_codec_context); + encoder->get_textures(encoder, textures, num_textures, destination_color); } diff --git a/src/encoder/video/vulkan.c b/src/encoder/video/vulkan.c index 4b0f1ea..802934d 100644 --- a/src/encoder/video/vulkan.c +++ b/src/encoder/video/vulkan.c @@ -3,8 +3,16 @@ #include "../../../include/egl.h" #include <libavcodec/avcodec.h> +#define VK_NO_PROTOTYPES #include <libavutil/hwcontext_vulkan.h> +//#include <vulkan/vulkan_core.h> + +#define GL_HANDLE_TYPE_OPAQUE_FD_EXT 0x9586 +#define GL_TEXTURE_TILING_EXT 0x9580 +#define GL_OPTIMAL_TILING_EXT 0x9584 +#define GL_LINEAR_TILING_EXT 0x9585 + typedef struct { gsr_video_encoder_vulkan_params params; unsigned int target_textures[2]; @@ -12,8 +20,12 @@ typedef struct { } gsr_video_encoder_vulkan; static bool gsr_video_encoder_vulkan_setup_context(gsr_video_encoder_vulkan *self, AVCodecContext *video_codec_context) { + AVDictionary *options = NULL; + //av_dict_set(&options, "linear_images", "1", 0); + //av_dict_set(&options, "disable_multiplane", "1", 0); +#if 0 // TODO: Use correct device - if(av_hwdevice_ctx_create(&self->device_ctx, AV_HWDEVICE_TYPE_VULKAN, NULL, NULL, 0) < 0) { + if(av_hwdevice_ctx_create(&self->device_ctx, AV_HWDEVICE_TYPE_VULKAN, NULL, options, 0) < 0) { fprintf(stderr, "gsr error: gsr_video_encoder_vulkan_setup_context: failed to create hardware device context\n"); return false; } @@ -32,6 +44,7 @@ static bool gsr_video_encoder_vulkan_setup_context(gsr_video_encoder_vulkan *sel hw_frame_context->format = video_codec_context->pix_fmt; hw_frame_context->device_ctx = (AVHWDeviceContext*)self->device_ctx->data; + //AVVulkanFramesContext *vk_frame_ctx = (AVVulkanFramesContext*)hw_frame_context->hwctx; //hw_frame_context->initial_pool_size = 20; if (av_hwframe_ctx_init(frame_context) < 0) { @@ -44,15 +57,175 @@ static bool gsr_video_encoder_vulkan_setup_context(gsr_video_encoder_vulkan *sel video_codec_context->hw_frames_ctx = av_buffer_ref(frame_context); av_buffer_unref(&frame_context); +#endif return true; } +static AVVulkanDeviceContext* video_codec_context_get_vulkan_data(AVCodecContext *video_codec_context) { + AVBufferRef *hw_frames_ctx = video_codec_context->hw_frames_ctx; + if(!hw_frames_ctx) + return NULL; + + AVHWFramesContext *hw_frame_context = (AVHWFramesContext*)hw_frames_ctx->data; + AVHWDeviceContext *device_context = (AVHWDeviceContext*)hw_frame_context->device_ctx; + if(device_context->type != AV_HWDEVICE_TYPE_VULKAN) + return NULL; + + return (AVVulkanDeviceContext*)device_context->hwctx; +} + +static uint32_t get_memory_type_idx(VkPhysicalDevice pdev, const VkMemoryRequirements *mem_reqs, VkMemoryPropertyFlagBits prop_flags, PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties) { + VkPhysicalDeviceMemoryProperties pdev_mem_props; + uint32_t i; + + vkGetPhysicalDeviceMemoryProperties(pdev, &pdev_mem_props); + + for (i = 0; i < pdev_mem_props.memoryTypeCount; i++) { + const VkMemoryType *type = &pdev_mem_props.memoryTypes[i]; + + if ((mem_reqs->memoryTypeBits & (1 << i)) && + (type->propertyFlags & prop_flags) == prop_flags) { + return i; + break; + } + } + return UINT32_MAX; +} + static bool gsr_video_encoder_vulkan_setup_textures(gsr_video_encoder_vulkan *self, AVCodecContext *video_codec_context, AVFrame *frame) { const int res = av_hwframe_get_buffer(video_codec_context->hw_frames_ctx, frame, 0); if(res < 0) { fprintf(stderr, "gsr error: gsr_video_encoder_vulkan_setup_textures: av_hwframe_get_buffer failed: %d\n", res); return false; } + + while(self->params.egl->glGetError()) {} +#if 0 + AVVkFrame *target_surface_id = (AVVkFrame*)frame->data[0]; + AVVulkanDeviceContext* vv = video_codec_context_get_vulkan_data(video_codec_context); + const size_t luma_size = frame->width * frame->height; + if(vv) { + PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements = (PFN_vkGetImageMemoryRequirements)vv->get_proc_addr(vv->inst, "vkGetImageMemoryRequirements"); + PFN_vkAllocateMemory vkAllocateMemory = (PFN_vkAllocateMemory)vv->get_proc_addr(vv->inst, "vkAllocateMemory"); + PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties = (PFN_vkGetPhysicalDeviceMemoryProperties)vv->get_proc_addr(vv->inst, "vkGetPhysicalDeviceMemoryProperties"); + PFN_vkGetMemoryFdKHR vkGetMemoryFdKHR = (PFN_vkGetMemoryFdKHR)vv->get_proc_addr(vv->inst, "vkGetMemoryFdKHR"); + + VkMemoryRequirements mem_reqs = {0}; + vkGetImageMemoryRequirements(vv->act_dev, target_surface_id->img[0], &mem_reqs); + + fprintf(stderr, "size: %lu, alignment: %lu, memory bits: 0x%08x\n", mem_reqs.size, mem_reqs.alignment, mem_reqs.memoryTypeBits); + VkDeviceMemory mem; + { + VkExportMemoryAllocateInfo exp_mem_info; + VkMemoryAllocateInfo mem_alloc_info; + VkMemoryDedicatedAllocateInfoKHR ded_info; + + memset(&exp_mem_info, 0, sizeof(exp_mem_info)); + exp_mem_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO; + exp_mem_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + + memset(&ded_info, 0, sizeof(ded_info)); + ded_info.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO; + ded_info.image = target_surface_id->img[0]; + + exp_mem_info.pNext = &ded_info; + + memset(&mem_alloc_info, 0, sizeof(mem_alloc_info)); + mem_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + mem_alloc_info.pNext = &exp_mem_info; + mem_alloc_info.allocationSize = target_surface_id->size[0]; + mem_alloc_info.memoryTypeIndex = get_memory_type_idx(vv->phys_dev, &mem_reqs, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vkGetPhysicalDeviceMemoryProperties); + + if (mem_alloc_info.memoryTypeIndex == UINT32_MAX) { + fprintf(stderr, "No suitable memory type index found.\n"); + return VK_NULL_HANDLE; + } + + if (vkAllocateMemory(vv->act_dev, &mem_alloc_info, 0, &mem) != + VK_SUCCESS) + return VK_NULL_HANDLE; + + fprintf(stderr, "memory: %p\n", (void*)mem); + + } + + fprintf(stderr, "target surface id: %p, %zu, %zu\n", (void*)target_surface_id->mem[0], target_surface_id->offset[0], target_surface_id->offset[1]); + fprintf(stderr, "vkGetMemoryFdKHR: %p\n", (void*)vkGetMemoryFdKHR); + + int fd = 0; + VkMemoryGetFdInfoKHR fd_info; + memset(&fd_info, 0, sizeof(fd_info)); + fd_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR; + fd_info.memory = target_surface_id->mem[0]; + fd_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + if(vkGetMemoryFdKHR(vv->act_dev, &fd_info, &fd) != VK_SUCCESS) { + fprintf(stderr, "failed!\n"); + } else { + fprintf(stderr, "fd: %d\n", fd); + } + + fprintf(stderr, "glImportMemoryFdEXT: %p, size: %zu\n", (void*)self->params.egl->glImportMemoryFdEXT, target_surface_id->size[0]); + const int tiling = target_surface_id->tiling == VK_IMAGE_TILING_LINEAR ? GL_LINEAR_TILING_EXT : GL_OPTIMAL_TILING_EXT; + + if(tiling != GL_OPTIMAL_TILING_EXT) { + fprintf(stderr, "tiling %d is not supported, only GL_OPTIMAL_TILING_EXT (%d) is supported\n", tiling, GL_OPTIMAL_TILING_EXT); + } + + + unsigned int gl_memory_obj = 0; + self->params.egl->glCreateMemoryObjectsEXT(1, &gl_memory_obj); + + //const int dedicated = GL_TRUE; + //self->params.egl->glMemoryObjectParameterivEXT(gl_memory_obj, GL_DEDICATED_MEMORY_OBJECT_EXT, &dedicated); + + self->params.egl->glImportMemoryFdEXT(gl_memory_obj, target_surface_id->size[0], GL_HANDLE_TYPE_OPAQUE_FD_EXT, fd); + if(!self->params.egl->glIsMemoryObjectEXT(gl_memory_obj)) + fprintf(stderr, "failed to create object!\n"); + + fprintf(stderr, "gl memory obj: %u, error: %d\n", gl_memory_obj, self->params.egl->glGetError()); + + // fprintf(stderr, "0 gl error: %d\n", self->params.egl->glGetError()); + // unsigned int vertex_buffer = 0; + // self->params.egl->glGenBuffers(1, &vertex_buffer); + // self->params.egl->glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); + // self->params.egl->glBufferStorageMemEXT(GL_ARRAY_BUFFER, target_surface_id->size[0], gl_memory_obj, target_surface_id->offset[0]); + // fprintf(stderr, "1 gl error: %d\n", self->params.egl->glGetError()); + + // fprintf(stderr, "0 gl error: %d\n", self->params.egl->glGetError()); + // unsigned int buffer = 0; + // self->params.egl->glCreateBuffers(1, &buffer); + // self->params.egl->glNamedBufferStorageMemEXT(buffer, target_surface_id->size[0], gl_memory_obj, target_surface_id->offset[0]); + // fprintf(stderr, "1 gl error: %d\n", self->params.egl->glGetError()); + + self->params.egl->glGenTextures(1, &self->target_textures[0]); + self->params.egl->glBindTexture(GL_TEXTURE_2D, self->target_textures[0]); + + fprintf(stderr, "1 gl error: %d\n", self->params.egl->glGetError()); + self->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_TILING_EXT, tiling); + + fprintf(stderr, "tiling: %d\n", tiling); + + fprintf(stderr, "2 gl error: %d\n", self->params.egl->glGetError()); + self->params.egl->glTexStorageMem2DEXT(GL_TEXTURE_2D, 1, GL_R8, frame->width, frame->height, gl_memory_obj, target_surface_id->offset[0]); + + fprintf(stderr, "3 gl error: %d\n", self->params.egl->glGetError()); + self->params.egl->glBindTexture(GL_TEXTURE_2D, 0); + + self->params.egl->glGenTextures(1, &self->target_textures[1]); + self->params.egl->glBindTexture(GL_TEXTURE_2D, self->target_textures[1]); + + fprintf(stderr, "1 gl error: %d\n", self->params.egl->glGetError()); + self->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_TILING_EXT, tiling); + + fprintf(stderr, "tiling: %d\n", tiling); + + fprintf(stderr, "2 gl error: %d\n", self->params.egl->glGetError()); + self->params.egl->glTexStorageMem2DEXT(GL_TEXTURE_2D, 1, GL_RG8, frame->width/2, frame->height/2, gl_memory_obj, target_surface_id->offset[0] + luma_size); + + fprintf(stderr, "3 gl error: %d\n", self->params.egl->glGetError()); + self->params.egl->glBindTexture(GL_TEXTURE_2D, 0); + } +#endif return true; } @@ -61,6 +234,18 @@ static void gsr_video_encoder_vulkan_stop(gsr_video_encoder_vulkan *self, AVCode static bool gsr_video_encoder_vulkan_start(gsr_video_encoder *encoder, AVCodecContext *video_codec_context, AVFrame *frame) { gsr_video_encoder_vulkan *self = encoder->priv; + video_codec_context->width = FFALIGN(video_codec_context->width, 2); + video_codec_context->height = FFALIGN(video_codec_context->height, 2); + + if(video_codec_context->width < 128) + video_codec_context->width = 128; + + if(video_codec_context->height < 128) + video_codec_context->height = 128; + + frame->width = video_codec_context->width; + frame->height = video_codec_context->height; + if(!gsr_video_encoder_vulkan_setup_context(self, video_codec_context)) { gsr_video_encoder_vulkan_stop(self, video_codec_context); return false; |