mirror of
https://github.com/morgan9e/grd
synced 2026-04-13 16:04:13 +09:00
750 lines
24 KiB
C
750 lines
24 KiB
C
/*
|
|
* Copyright (C) 2023 Pascal Nowack
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|
* 02111-1307, USA.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "grd-rdp-render-context.h"
|
|
|
|
#include <drm_fourcc.h>
|
|
|
|
#include "grd-context.h"
|
|
#include "grd-debug.h"
|
|
#include "grd-encode-session.h"
|
|
#include "grd-encode-session-ca-sw.h"
|
|
#include "grd-hwaccel-vaapi.h"
|
|
#include "grd-image-view.h"
|
|
#include "grd-rdp-buffer-info.h"
|
|
#include "grd-rdp-damage-detector.h"
|
|
#include "grd-rdp-dvc-graphics-pipeline.h"
|
|
#include "grd-rdp-frame.h"
|
|
#include "grd-rdp-gfx-frame-controller.h"
|
|
#include "grd-rdp-gfx-framerate-log.h"
|
|
#include "grd-rdp-gfx-surface.h"
|
|
#include "grd-rdp-render-state.h"
|
|
#include "grd-rdp-renderer.h"
|
|
#include "grd-rdp-server.h"
|
|
#include "grd-rdp-surface.h"
|
|
#include "grd-rdp-surface-renderer.h"
|
|
#include "grd-rdp-view-creator-avc.h"
|
|
#include "grd-rdp-view-creator-gen-gl.h"
|
|
#include "grd-rdp-view-creator-gen-sw.h"
|
|
#include "grd-utils.h"
|
|
#include "grd-vk-device.h"
|
|
|
|
#define STATE_TILE_WIDTH 64
|
|
#define STATE_TILE_HEIGHT 64
|
|
|
|
struct _GrdRdpRenderContext
|
|
{
|
|
GObject parent;
|
|
|
|
GrdRdpRenderer *renderer;
|
|
|
|
GrdRdpCodec codec;
|
|
|
|
GrdRdpGfxSurface *gfx_surface;
|
|
GrdRdpViewCreator *view_creator;
|
|
GrdEncodeSession *encode_session;
|
|
|
|
GHashTable *image_views;
|
|
GHashTable *acquired_image_views;
|
|
|
|
GrdImageView *last_acquired_image_view;
|
|
|
|
gboolean delay_view_finalization;
|
|
|
|
uint32_t *chroma_state_buffer;
|
|
uint32_t state_buffer_length;
|
|
};
|
|
|
|
G_DEFINE_TYPE (GrdRdpRenderContext, grd_rdp_render_context, G_TYPE_OBJECT)
|
|
|
|
GrdRdpRenderer *
|
|
grd_rdp_render_context_get_renderer (GrdRdpRenderContext *render_context)
|
|
{
|
|
return render_context->renderer;
|
|
}
|
|
|
|
GrdRdpCodec
|
|
grd_rdp_render_context_get_codec (GrdRdpRenderContext *render_context)
|
|
{
|
|
return render_context->codec;
|
|
}
|
|
|
|
GrdRdpGfxSurface *
|
|
grd_rdp_render_context_get_gfx_surface (GrdRdpRenderContext *render_context)
|
|
{
|
|
return render_context->gfx_surface;
|
|
}
|
|
|
|
GrdRdpViewCreator *
|
|
grd_rdp_render_context_get_view_creator (GrdRdpRenderContext *render_context)
|
|
{
|
|
return render_context->view_creator;
|
|
}
|
|
|
|
GrdEncodeSession *
|
|
grd_rdp_render_context_get_encode_session (GrdRdpRenderContext *render_context)
|
|
{
|
|
return render_context->encode_session;
|
|
}
|
|
|
|
gboolean
|
|
grd_rdp_render_context_must_delay_view_finalization (GrdRdpRenderContext *render_context)
|
|
{
|
|
return render_context->delay_view_finalization;
|
|
}
|
|
|
|
gboolean
|
|
grd_rdp_render_context_should_avoid_dual_frame (GrdRdpRenderContext *render_context)
|
|
{
|
|
GrdRdpGfxSurface *gfx_surface = render_context->gfx_surface;
|
|
GrdRdpGfxFrameController *frame_controller;
|
|
GrdRdpGfxFramerateLog *framerate_log;
|
|
|
|
g_assert (gfx_surface);
|
|
|
|
frame_controller = grd_rdp_gfx_surface_get_frame_controller (gfx_surface);
|
|
framerate_log = grd_rdp_gfx_frame_controller_get_framerate_log (frame_controller);
|
|
|
|
return grd_rdp_gfx_framerate_log_should_avoid_dual_frame (framerate_log);
|
|
}
|
|
|
|
static void
|
|
notify_frame_upgrade_state (GrdRdpRenderContext *render_context,
|
|
gboolean can_upgrade_frame)
|
|
{
|
|
GrdRdpGfxSurface *gfx_surface = render_context->gfx_surface;
|
|
GrdRdpSurface *rdp_surface;
|
|
GrdRdpSurfaceRenderer *surface_renderer;
|
|
|
|
g_assert (gfx_surface);
|
|
rdp_surface = grd_rdp_gfx_surface_get_rdp_surface (gfx_surface);
|
|
surface_renderer = grd_rdp_surface_get_surface_renderer (rdp_surface);
|
|
|
|
grd_rdp_surface_renderer_notify_frame_upgrade_state (surface_renderer,
|
|
can_upgrade_frame);
|
|
}
|
|
|
|
static void
|
|
update_frame_upgrade_state (GrdRdpRenderContext *render_context)
|
|
{
|
|
gboolean can_upgrade_frame;
|
|
|
|
can_upgrade_frame =
|
|
!!render_context->chroma_state_buffer &&
|
|
g_hash_table_size (render_context->acquired_image_views) == 0;
|
|
|
|
notify_frame_upgrade_state (render_context, can_upgrade_frame);
|
|
}
|
|
|
|
GrdImageView *
|
|
grd_rdp_render_context_acquire_image_view (GrdRdpRenderContext *render_context)
|
|
{
|
|
GrdImageView *image_view = NULL;
|
|
GHashTableIter iter;
|
|
|
|
g_hash_table_iter_init (&iter, render_context->image_views);
|
|
while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &image_view))
|
|
{
|
|
if (g_hash_table_contains (render_context->acquired_image_views,
|
|
image_view))
|
|
continue;
|
|
|
|
g_hash_table_add (render_context->acquired_image_views, image_view);
|
|
render_context->last_acquired_image_view = image_view;
|
|
|
|
update_frame_upgrade_state (render_context);
|
|
|
|
return image_view;
|
|
}
|
|
|
|
g_assert_not_reached ();
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
grd_rdp_render_context_release_image_view (GrdRdpRenderContext *render_context,
|
|
GrdImageView *image_view)
|
|
{
|
|
if (!g_hash_table_remove (render_context->acquired_image_views, image_view))
|
|
g_assert_not_reached ();
|
|
|
|
grd_image_view_notify_image_view_release (image_view);
|
|
update_frame_upgrade_state (render_context);
|
|
}
|
|
|
|
static void
|
|
maybe_downgrade_view_type (GrdRdpRenderContext *render_context,
|
|
GrdRdpFrame *rdp_frame)
|
|
{
|
|
GrdRdpFrameViewType view_type;
|
|
|
|
view_type = grd_rdp_frame_get_avc_view_type (rdp_frame);
|
|
if (view_type != GRD_RDP_FRAME_VIEW_TYPE_DUAL)
|
|
return;
|
|
|
|
if (grd_rdp_render_context_should_avoid_dual_frame (render_context))
|
|
grd_rdp_frame_set_avc_view_type (rdp_frame, GRD_RDP_FRAME_VIEW_TYPE_MAIN);
|
|
}
|
|
|
|
static gboolean
|
|
is_auxiliary_view_needed (GrdRdpRenderState *render_state)
|
|
{
|
|
uint32_t *chroma_state_buffer =
|
|
grd_rdp_render_state_get_chroma_state_buffer (render_state);
|
|
uint32_t state_buffer_length =
|
|
grd_rdp_render_state_get_state_buffer_length (render_state);
|
|
uint32_t i;
|
|
|
|
for (i = 0; i < state_buffer_length; ++i)
|
|
{
|
|
if (chroma_state_buffer[i] != 0)
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
update_dual_frame (GrdRdpRenderContext *render_context,
|
|
GrdRdpFrame *rdp_frame,
|
|
GrdRdpRenderState *render_state)
|
|
{
|
|
uint32_t *damage_buffer =
|
|
grd_rdp_render_state_get_damage_buffer (render_state);
|
|
uint32_t state_buffer_length =
|
|
grd_rdp_render_state_get_state_buffer_length (render_state);
|
|
uint32_t i;
|
|
|
|
if (!render_context->chroma_state_buffer)
|
|
{
|
|
if (!is_auxiliary_view_needed (render_state))
|
|
{
|
|
grd_rdp_frame_set_avc_view_type (rdp_frame,
|
|
GRD_RDP_FRAME_VIEW_TYPE_MAIN);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
g_assert (render_context->state_buffer_length == state_buffer_length);
|
|
|
|
for (i = 0; i < render_context->state_buffer_length; ++i)
|
|
{
|
|
if (render_context->chroma_state_buffer[i] != 0)
|
|
damage_buffer[i] = 1;
|
|
}
|
|
g_clear_pointer (&render_context->chroma_state_buffer, g_free);
|
|
}
|
|
|
|
static void
|
|
update_main_frame (GrdRdpRenderContext *render_context,
|
|
GrdRdpFrame *rdp_frame,
|
|
GrdRdpRenderState *render_state)
|
|
{
|
|
uint32_t *damage_buffer =
|
|
grd_rdp_render_state_get_damage_buffer (render_state);
|
|
uint32_t *chroma_state_buffer =
|
|
grd_rdp_render_state_get_chroma_state_buffer (render_state);
|
|
uint32_t state_buffer_length =
|
|
grd_rdp_render_state_get_state_buffer_length (render_state);
|
|
gboolean pending_auxiliary_view = FALSE;
|
|
uint32_t i;
|
|
|
|
if (!render_context->chroma_state_buffer)
|
|
{
|
|
if (is_auxiliary_view_needed (render_state))
|
|
{
|
|
render_context->chroma_state_buffer =
|
|
g_memdup2 (chroma_state_buffer,
|
|
state_buffer_length * sizeof (uint32_t));
|
|
render_context->state_buffer_length = state_buffer_length;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
g_assert (render_context->state_buffer_length == state_buffer_length);
|
|
|
|
for (i = 0; i < render_context->state_buffer_length; ++i)
|
|
{
|
|
if (chroma_state_buffer[i] != 0)
|
|
render_context->chroma_state_buffer[i] = 1;
|
|
else if (damage_buffer[i] != 0)
|
|
render_context->chroma_state_buffer[i] = 0;
|
|
|
|
if (render_context->chroma_state_buffer[i] != 0)
|
|
pending_auxiliary_view = TRUE;
|
|
}
|
|
if (!pending_auxiliary_view)
|
|
g_clear_pointer (&render_context->chroma_state_buffer, g_free);
|
|
}
|
|
|
|
static void
|
|
update_avc444_render_state (GrdRdpRenderContext *render_context,
|
|
GrdRdpFrame *rdp_frame,
|
|
GrdRdpRenderState *render_state)
|
|
{
|
|
maybe_downgrade_view_type (render_context, rdp_frame);
|
|
|
|
switch (grd_rdp_frame_get_avc_view_type (rdp_frame))
|
|
{
|
|
case GRD_RDP_FRAME_VIEW_TYPE_DUAL:
|
|
update_dual_frame (render_context, rdp_frame, render_state);
|
|
break;
|
|
case GRD_RDP_FRAME_VIEW_TYPE_MAIN:
|
|
update_main_frame (render_context, rdp_frame, render_state);
|
|
break;
|
|
case GRD_RDP_FRAME_VIEW_TYPE_AUX:
|
|
g_assert_not_reached ();
|
|
break;
|
|
}
|
|
update_frame_upgrade_state (render_context);
|
|
}
|
|
|
|
static cairo_region_t *
|
|
create_damage_region (GrdRdpRenderContext *render_context,
|
|
GrdRdpRenderState *render_state)
|
|
{
|
|
GrdRdpGfxSurface *gfx_surface = render_context->gfx_surface;
|
|
uint32_t *damage_buffer =
|
|
grd_rdp_render_state_get_damage_buffer (render_state);
|
|
GrdRdpSurface *rdp_surface;
|
|
uint32_t surface_width;
|
|
uint32_t surface_height;
|
|
uint32_t state_buffer_width;
|
|
uint32_t state_buffer_height;
|
|
uint32_t state_buffer_stride;
|
|
cairo_region_t *damage_region;
|
|
uint32_t x, y;
|
|
|
|
g_assert (gfx_surface);
|
|
rdp_surface = grd_rdp_gfx_surface_get_rdp_surface (gfx_surface);
|
|
|
|
surface_width = grd_rdp_surface_get_width (rdp_surface);
|
|
surface_height = grd_rdp_surface_get_height (rdp_surface);
|
|
|
|
state_buffer_width = grd_get_aligned_size (surface_width, 64) / 64;
|
|
state_buffer_height = grd_get_aligned_size (surface_height, 64) / 64;
|
|
state_buffer_stride = state_buffer_width;
|
|
|
|
damage_region = cairo_region_create ();
|
|
g_assert (cairo_region_status (damage_region) == CAIRO_STATUS_SUCCESS);
|
|
|
|
for (y = 0; y < state_buffer_height; ++y)
|
|
{
|
|
for (x = 0; x < state_buffer_width; ++x)
|
|
{
|
|
cairo_rectangle_int_t tile = {};
|
|
uint32_t target_pos;
|
|
|
|
target_pos = y * state_buffer_stride + x;
|
|
if (damage_buffer[target_pos] == 0)
|
|
continue;
|
|
|
|
tile.x = x * STATE_TILE_WIDTH;
|
|
tile.y = y * STATE_TILE_HEIGHT;
|
|
tile.width = surface_width - tile.x < STATE_TILE_WIDTH ?
|
|
surface_width - tile.x : STATE_TILE_WIDTH;
|
|
tile.height = surface_height - tile.y < STATE_TILE_HEIGHT ?
|
|
surface_height - tile.y : STATE_TILE_HEIGHT;
|
|
|
|
cairo_region_union_rectangle (damage_region, &tile);
|
|
}
|
|
}
|
|
|
|
return damage_region;
|
|
}
|
|
|
|
void
|
|
grd_rdp_render_context_update_frame_state (GrdRdpRenderContext *render_context,
|
|
GrdRdpFrame *rdp_frame,
|
|
GrdRdpRenderState *render_state)
|
|
{
|
|
cairo_region_t *damage_region;
|
|
|
|
switch (render_context->codec)
|
|
{
|
|
case GRD_RDP_CODEC_CAPROGRESSIVE:
|
|
case GRD_RDP_CODEC_AVC420:
|
|
break;
|
|
case GRD_RDP_CODEC_AVC444v2:
|
|
update_avc444_render_state (render_context, rdp_frame, render_state);
|
|
break;
|
|
}
|
|
|
|
damage_region = create_damage_region (render_context, render_state);
|
|
grd_rdp_frame_set_damage_region (rdp_frame, damage_region);
|
|
|
|
grd_rdp_render_state_free (render_state);
|
|
}
|
|
|
|
void
|
|
grd_rdp_render_context_fetch_progressive_render_state (GrdRdpRenderContext *render_context,
|
|
GrdImageView **image_view,
|
|
cairo_region_t **damage_region)
|
|
{
|
|
g_autoptr (GrdRdpRenderState) render_state = NULL;
|
|
|
|
g_assert (render_context->chroma_state_buffer);
|
|
|
|
render_state = grd_rdp_render_state_new (render_context->chroma_state_buffer,
|
|
NULL,
|
|
render_context->state_buffer_length);
|
|
*damage_region = create_damage_region (render_context, render_state);
|
|
|
|
*image_view = render_context->last_acquired_image_view;
|
|
g_assert (!g_hash_table_contains (render_context->acquired_image_views,
|
|
*image_view));
|
|
|
|
g_hash_table_add (render_context->acquired_image_views, *image_view);
|
|
|
|
g_clear_pointer (&render_context->chroma_state_buffer, g_free);
|
|
update_frame_upgrade_state (render_context);
|
|
}
|
|
|
|
static gboolean
|
|
is_gpu_driver_amd (GrdRdpRenderContext *render_context)
|
|
{
|
|
GrdVkDevice *vk_device =
|
|
grd_rdp_renderer_get_vk_device (render_context->renderer);
|
|
VkDriverId driver_id = grd_vk_device_get_driver_id (vk_device);
|
|
|
|
return driver_id == VK_DRIVER_ID_AMD_PROPRIETARY ||
|
|
driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE ||
|
|
driver_id == VK_DRIVER_ID_MESA_RADV;
|
|
}
|
|
|
|
static void
|
|
try_create_vaapi_session (GrdRdpRenderContext *render_context,
|
|
GrdRdpSurface *rdp_surface,
|
|
gboolean have_avc444)
|
|
{
|
|
GrdVkDevice *vk_device =
|
|
grd_rdp_renderer_get_vk_device (render_context->renderer);
|
|
GrdRdpSurfaceRenderer *surface_renderer =
|
|
grd_rdp_surface_get_surface_renderer (rdp_surface);
|
|
GrdHwAccelVaapi *hwaccel_vaapi =
|
|
grd_rdp_renderer_get_hwaccel_vaapi (render_context->renderer);
|
|
GrdRdpBufferInfo *buffer_info =
|
|
grd_rdp_surface_renderer_get_buffer_info (surface_renderer);
|
|
uint32_t refresh_rate =
|
|
grd_rdp_surface_renderer_get_refresh_rate (surface_renderer);
|
|
uint32_t surface_width = grd_rdp_surface_get_width (rdp_surface);
|
|
uint32_t surface_height = grd_rdp_surface_get_height (rdp_surface);
|
|
g_autoptr (GrdEncodeSession) encode_session = NULL;
|
|
GrdRdpViewCreatorAVC *view_creator_avc;
|
|
uint32_t render_surface_width = 0;
|
|
uint32_t render_surface_height = 0;
|
|
g_autoptr (GError) error = NULL;
|
|
g_autoptr (GList) image_views = NULL;
|
|
GList *l;
|
|
|
|
g_assert (buffer_info->buffer_type == GRD_RDP_BUFFER_TYPE_DMA_BUF);
|
|
|
|
if (!buffer_info->has_vk_image)
|
|
return;
|
|
if (buffer_info->drm_format_modifier == DRM_FORMAT_MOD_INVALID)
|
|
return;
|
|
|
|
encode_session =
|
|
grd_hwaccel_vaapi_create_encode_session (hwaccel_vaapi,
|
|
surface_width, surface_height,
|
|
refresh_rate, &error);
|
|
if (!encode_session)
|
|
{
|
|
g_debug ("[HWAccel.VAAPI] Could not create VAAPI encode session: %s",
|
|
error->message);
|
|
return;
|
|
}
|
|
|
|
grd_encode_session_get_surface_size (encode_session,
|
|
&render_surface_width,
|
|
&render_surface_height);
|
|
|
|
g_assert (render_surface_width % 16 == 0);
|
|
g_assert (render_surface_height % 16 == 0);
|
|
g_assert (render_surface_width >= 16);
|
|
g_assert (render_surface_height >= 16);
|
|
|
|
view_creator_avc =
|
|
grd_rdp_view_creator_avc_new (vk_device,
|
|
render_surface_width,
|
|
render_surface_height,
|
|
surface_width,
|
|
surface_height,
|
|
&error);
|
|
if (!view_creator_avc)
|
|
{
|
|
g_debug ("[HWAccel.Vulkan] Failed to create view creator for VAAPI "
|
|
"encode session: %s", error->message);
|
|
return;
|
|
}
|
|
|
|
image_views = grd_encode_session_get_image_views (encode_session);
|
|
for (l = image_views; l; l = l->next)
|
|
{
|
|
GrdImageView *image_view = l->data;
|
|
|
|
g_hash_table_add (render_context->image_views, image_view);
|
|
}
|
|
|
|
render_context->view_creator = GRD_RDP_VIEW_CREATOR (view_creator_avc);
|
|
render_context->encode_session = g_steal_pointer (&encode_session);
|
|
|
|
if (have_avc444)
|
|
render_context->codec = GRD_RDP_CODEC_AVC444v2;
|
|
else
|
|
render_context->codec = GRD_RDP_CODEC_AVC420;
|
|
|
|
g_debug ("[HWAccel.VAAPI] Created VAAPI encode session for surface with "
|
|
"size %ux%u", surface_width, surface_height);
|
|
}
|
|
|
|
static gboolean
|
|
create_egl_based_rfx_progressive_encode_session (GrdRdpRenderContext *render_context,
|
|
GrdRdpSurface *rdp_surface,
|
|
GError **error)
|
|
{
|
|
GrdRdpSwEncoderCa *encoder_ca =
|
|
grd_rdp_renderer_get_encoder_ca (render_context->renderer);
|
|
uint32_t surface_width = grd_rdp_surface_get_width (rdp_surface);
|
|
uint32_t surface_height = grd_rdp_surface_get_height (rdp_surface);
|
|
GrdEncodeSessionCaSw *encode_session_ca;
|
|
GrdRdpViewCreatorGenGL *view_creator_gen_gl;
|
|
GrdEncodeSession *encode_session;
|
|
g_autoptr (GList) image_views = NULL;
|
|
GList *l;
|
|
|
|
encode_session_ca =
|
|
grd_encode_session_ca_sw_new (encoder_ca,
|
|
surface_width, surface_height,
|
|
error);
|
|
if (!encode_session_ca)
|
|
return FALSE;
|
|
|
|
view_creator_gen_gl =
|
|
grd_rdp_view_creator_gen_gl_new (render_context, surface_width, surface_height);
|
|
|
|
encode_session = GRD_ENCODE_SESSION (encode_session_ca);
|
|
image_views = grd_encode_session_get_image_views (encode_session);
|
|
|
|
for (l = image_views; l; l = l->next)
|
|
{
|
|
GrdImageView *image_view = l->data;
|
|
|
|
g_hash_table_add (render_context->image_views, image_view);
|
|
}
|
|
|
|
render_context->view_creator = GRD_RDP_VIEW_CREATOR (view_creator_gen_gl);
|
|
render_context->encode_session = encode_session;
|
|
|
|
render_context->codec = GRD_RDP_CODEC_CAPROGRESSIVE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
create_hw_accelerated_encode_session (GrdRdpRenderContext *render_context,
|
|
GrdRdpSurface *rdp_surface,
|
|
GError **error)
|
|
{
|
|
GrdSessionRdp *session_rdp =
|
|
grd_rdp_renderer_get_session (render_context->renderer);
|
|
GrdRdpDvcGraphicsPipeline *graphics_pipeline =
|
|
grd_session_rdp_get_graphics_pipeline (session_rdp);
|
|
GrdHwAccelVaapi *hwaccel_vaapi =
|
|
grd_rdp_renderer_get_hwaccel_vaapi (render_context->renderer);
|
|
gboolean have_avc444 = FALSE;
|
|
gboolean have_avc420 = FALSE;
|
|
|
|
grd_rdp_dvc_graphics_pipeline_get_capabilities (graphics_pipeline,
|
|
&have_avc444, &have_avc420);
|
|
if ((have_avc444 || have_avc420) && hwaccel_vaapi &&
|
|
!is_gpu_driver_amd (render_context) &&
|
|
grd_get_debug_flags () & GRD_DEBUG_VKVA)
|
|
try_create_vaapi_session (render_context, rdp_surface, have_avc444);
|
|
|
|
if (render_context->encode_session)
|
|
return TRUE;
|
|
|
|
return create_egl_based_rfx_progressive_encode_session (render_context,
|
|
rdp_surface,
|
|
error);
|
|
}
|
|
|
|
static gboolean
|
|
create_sw_based_rfx_progressive_encode_session (GrdRdpRenderContext *render_context,
|
|
GrdRdpSurface *rdp_surface,
|
|
GError **error)
|
|
{
|
|
GrdRdpSwEncoderCa *encoder_ca =
|
|
grd_rdp_renderer_get_encoder_ca (render_context->renderer);
|
|
uint32_t surface_width = grd_rdp_surface_get_width (rdp_surface);
|
|
uint32_t surface_height = grd_rdp_surface_get_height (rdp_surface);
|
|
GrdEncodeSessionCaSw *encode_session_ca;
|
|
GrdRdpViewCreatorGenSW *view_creator_gen_sw;
|
|
GrdEncodeSession *encode_session;
|
|
g_autoptr (GList) image_views = NULL;
|
|
GList *l;
|
|
|
|
encode_session_ca =
|
|
grd_encode_session_ca_sw_new (encoder_ca,
|
|
surface_width, surface_height,
|
|
error);
|
|
if (!encode_session_ca)
|
|
return FALSE;
|
|
|
|
view_creator_gen_sw = grd_rdp_view_creator_gen_sw_new (surface_width,
|
|
surface_height);
|
|
|
|
encode_session = GRD_ENCODE_SESSION (encode_session_ca);
|
|
image_views = grd_encode_session_get_image_views (encode_session);
|
|
|
|
for (l = image_views; l; l = l->next)
|
|
{
|
|
GrdImageView *image_view = l->data;
|
|
|
|
g_hash_table_add (render_context->image_views, image_view);
|
|
}
|
|
|
|
render_context->view_creator = GRD_RDP_VIEW_CREATOR (view_creator_gen_sw);
|
|
render_context->encode_session = encode_session;
|
|
|
|
render_context->codec = GRD_RDP_CODEC_CAPROGRESSIVE;
|
|
render_context->delay_view_finalization = TRUE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
create_sw_based_encode_session (GrdRdpRenderContext *render_context,
|
|
GrdRdpSurface *rdp_surface,
|
|
GError **error)
|
|
{
|
|
return create_sw_based_rfx_progressive_encode_session (render_context,
|
|
rdp_surface,
|
|
error);
|
|
}
|
|
|
|
static gboolean
|
|
create_encode_session (GrdRdpRenderContext *render_context,
|
|
GrdRdpSurface *rdp_surface,
|
|
GError **error)
|
|
{
|
|
GrdRdpSurfaceRenderer *surface_renderer =
|
|
grd_rdp_surface_get_surface_renderer (rdp_surface);
|
|
GrdRdpBufferInfo *buffer_info =
|
|
grd_rdp_surface_renderer_get_buffer_info (surface_renderer);
|
|
|
|
switch (buffer_info->buffer_type)
|
|
{
|
|
case GRD_RDP_BUFFER_TYPE_DMA_BUF:
|
|
return create_hw_accelerated_encode_session (render_context,
|
|
rdp_surface,
|
|
error);
|
|
case GRD_RDP_BUFFER_TYPE_MEM_FD:
|
|
return create_sw_based_encode_session (render_context,
|
|
rdp_surface,
|
|
error);
|
|
case GRD_RDP_BUFFER_TYPE_NONE:
|
|
g_assert_not_reached ();
|
|
return FALSE;
|
|
}
|
|
|
|
g_assert_not_reached ();
|
|
return FALSE;
|
|
}
|
|
|
|
GrdRdpRenderContext *
|
|
grd_rdp_render_context_new (GrdRdpRenderer *renderer,
|
|
GrdRdpSurface *rdp_surface)
|
|
{
|
|
GrdSessionRdp *session_rdp = grd_rdp_renderer_get_session (renderer);
|
|
GrdRdpDvcGraphicsPipeline *graphics_pipeline =
|
|
grd_session_rdp_get_graphics_pipeline (session_rdp);
|
|
g_autoptr (GrdRdpRenderContext) render_context = NULL;
|
|
g_autoptr (GError) error = NULL;
|
|
|
|
g_assert (graphics_pipeline);
|
|
|
|
if (!grd_rdp_damage_detector_invalidate_surface (rdp_surface->detector))
|
|
return NULL;
|
|
|
|
render_context = g_object_new (GRD_TYPE_RDP_RENDER_CONTEXT, NULL);
|
|
render_context->renderer = renderer;
|
|
render_context->gfx_surface =
|
|
grd_rdp_dvc_graphics_pipeline_acquire_gfx_surface (graphics_pipeline,
|
|
rdp_surface);
|
|
|
|
if (!create_encode_session (render_context, rdp_surface, &error))
|
|
{
|
|
g_warning ("[RDP] Failed to create encode session: %s", error->message);
|
|
return NULL;
|
|
}
|
|
|
|
return g_steal_pointer (&render_context);
|
|
}
|
|
|
|
static void
|
|
grd_rdp_render_context_dispose (GObject *object)
|
|
{
|
|
GrdRdpRenderContext *render_context = GRD_RDP_RENDER_CONTEXT (object);
|
|
|
|
if (render_context->acquired_image_views)
|
|
g_assert (g_hash_table_size (render_context->acquired_image_views) == 0);
|
|
|
|
g_clear_pointer (&render_context->chroma_state_buffer, g_free);
|
|
update_frame_upgrade_state (render_context);
|
|
|
|
g_clear_object (&render_context->view_creator);
|
|
g_clear_object (&render_context->encode_session);
|
|
g_clear_object (&render_context->gfx_surface);
|
|
|
|
G_OBJECT_CLASS (grd_rdp_render_context_parent_class)->dispose (object);
|
|
}
|
|
|
|
static void
|
|
grd_rdp_render_context_finalize (GObject *object)
|
|
{
|
|
GrdRdpRenderContext *render_context = GRD_RDP_RENDER_CONTEXT (object);
|
|
|
|
g_clear_pointer (&render_context->acquired_image_views, g_hash_table_unref);
|
|
g_clear_pointer (&render_context->image_views, g_hash_table_unref);
|
|
|
|
G_OBJECT_CLASS (grd_rdp_render_context_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
grd_rdp_render_context_init (GrdRdpRenderContext *render_context)
|
|
{
|
|
render_context->image_views = g_hash_table_new (NULL, NULL);
|
|
render_context->acquired_image_views = g_hash_table_new (NULL, NULL);
|
|
}
|
|
|
|
static void
|
|
grd_rdp_render_context_class_init (GrdRdpRenderContextClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
object_class->dispose = grd_rdp_render_context_dispose;
|
|
object_class->finalize = grd_rdp_render_context_finalize;
|
|
}
|