mirror of
https://github.com/morgan9e/grd
synced 2026-04-14 00:14:18 +09:00
.
This commit is contained in:
749
grd-rdp-render-context.c
Normal file
749
grd-rdp-render-context.c
Normal file
@@ -0,0 +1,749 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
Reference in New Issue
Block a user