mirror of
https://github.com/morgan9e/grd
synced 2026-04-14 00:14:18 +09:00
.
This commit is contained in:
382
grd-rdp-frame.c
Normal file
382
grd-rdp-frame.c
Normal file
@@ -0,0 +1,382 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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-frame.h"
|
||||
|
||||
#include "grd-encode-context.h"
|
||||
#include "grd-rdp-render-context.h"
|
||||
#include "grd-rdp-renderer.h"
|
||||
|
||||
struct _GrdRdpFrame
|
||||
{
|
||||
GrdRdpRenderer *renderer;
|
||||
GrdRdpRenderContext *render_context;
|
||||
|
||||
GrdRdpFrameCallback frame_picked_up;
|
||||
GrdRdpFrameCallback view_finalized;
|
||||
GrdRdpFrameCallback frame_submitted;
|
||||
GrdRdpFrameCallback frame_finalized;
|
||||
gpointer callback_user_data;
|
||||
GDestroyNotify user_data_destroy;
|
||||
|
||||
gboolean pending_view_finalization;
|
||||
|
||||
GrdEncodeContext *encode_context;
|
||||
|
||||
GList *acquired_image_views;
|
||||
GQueue *unused_image_views;
|
||||
|
||||
GrdRdpBuffer *src_buffer_new;
|
||||
GrdRdpBuffer *src_buffer_old;
|
||||
|
||||
GrdRdpFrameViewType view_type;
|
||||
|
||||
cairo_region_t *damage_region;
|
||||
GList *bitstreams;
|
||||
};
|
||||
|
||||
GrdRdpRenderer *
|
||||
grd_rdp_frame_get_renderer (GrdRdpFrame *rdp_frame)
|
||||
{
|
||||
return rdp_frame->renderer;
|
||||
}
|
||||
|
||||
GrdRdpRenderContext *
|
||||
grd_rdp_frame_get_render_context (GrdRdpFrame *rdp_frame)
|
||||
{
|
||||
return rdp_frame->render_context;
|
||||
}
|
||||
|
||||
GrdEncodeContext *
|
||||
grd_rdp_frame_get_encode_context (GrdRdpFrame *rdp_frame)
|
||||
{
|
||||
return rdp_frame->encode_context;
|
||||
}
|
||||
|
||||
GList *
|
||||
grd_rdp_frame_get_image_views (GrdRdpFrame *rdp_frame)
|
||||
{
|
||||
return rdp_frame->acquired_image_views;
|
||||
}
|
||||
|
||||
GrdRdpBuffer *
|
||||
grd_rdp_frame_get_source_buffer (GrdRdpFrame *rdp_frame)
|
||||
{
|
||||
return rdp_frame->src_buffer_new;
|
||||
}
|
||||
|
||||
GrdRdpBuffer *
|
||||
grd_rdp_frame_get_last_source_buffer (GrdRdpFrame *rdp_frame)
|
||||
{
|
||||
return rdp_frame->src_buffer_old;
|
||||
}
|
||||
|
||||
GrdRdpFrameViewType
|
||||
grd_rdp_frame_get_avc_view_type (GrdRdpFrame *rdp_frame)
|
||||
{
|
||||
return rdp_frame->view_type;
|
||||
}
|
||||
|
||||
cairo_region_t *
|
||||
grd_rdp_frame_get_damage_region (GrdRdpFrame *rdp_frame)
|
||||
{
|
||||
return rdp_frame->damage_region;
|
||||
}
|
||||
|
||||
GList *
|
||||
grd_rdp_frame_get_bitstreams (GrdRdpFrame *rdp_frame)
|
||||
{
|
||||
return rdp_frame->bitstreams;
|
||||
}
|
||||
|
||||
gboolean
|
||||
grd_rdp_frame_has_valid_view (GrdRdpFrame *rdp_frame)
|
||||
{
|
||||
return !!rdp_frame->damage_region;
|
||||
}
|
||||
|
||||
gboolean
|
||||
grd_rdp_frame_is_surface_damaged (GrdRdpFrame *rdp_frame)
|
||||
{
|
||||
return cairo_region_num_rectangles (rdp_frame->damage_region) > 0;
|
||||
}
|
||||
|
||||
void
|
||||
grd_rdp_frame_set_renderer (GrdRdpFrame *rdp_frame,
|
||||
GrdRdpRenderer *renderer)
|
||||
{
|
||||
rdp_frame->renderer = renderer;
|
||||
}
|
||||
|
||||
void
|
||||
grd_rdp_frame_set_avc_view_type (GrdRdpFrame *rdp_frame,
|
||||
GrdRdpFrameViewType view_type)
|
||||
{
|
||||
g_assert (view_type != GRD_RDP_FRAME_VIEW_TYPE_DUAL);
|
||||
g_assert (view_type == GRD_RDP_FRAME_VIEW_TYPE_MAIN ||
|
||||
view_type == GRD_RDP_FRAME_VIEW_TYPE_AUX);
|
||||
|
||||
switch (rdp_frame->view_type)
|
||||
{
|
||||
case GRD_RDP_FRAME_VIEW_TYPE_DUAL:
|
||||
g_assert (g_queue_get_length (rdp_frame->unused_image_views) == 2);
|
||||
g_queue_pop_tail (rdp_frame->unused_image_views);
|
||||
break;
|
||||
case GRD_RDP_FRAME_VIEW_TYPE_MAIN:
|
||||
case GRD_RDP_FRAME_VIEW_TYPE_AUX:
|
||||
g_assert (g_queue_get_length (rdp_frame->unused_image_views) == 1);
|
||||
break;
|
||||
}
|
||||
|
||||
rdp_frame->view_type = view_type;
|
||||
}
|
||||
|
||||
static void
|
||||
finalize_view (GrdRdpFrame *rdp_frame)
|
||||
{
|
||||
g_assert (rdp_frame->pending_view_finalization);
|
||||
|
||||
rdp_frame->view_finalized (rdp_frame, rdp_frame->callback_user_data);
|
||||
rdp_frame->pending_view_finalization = FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
grd_rdp_frame_set_damage_region (GrdRdpFrame *rdp_frame,
|
||||
cairo_region_t *damage_region)
|
||||
{
|
||||
GrdRdpRenderContext *render_context = rdp_frame->render_context;
|
||||
|
||||
g_assert (!rdp_frame->damage_region);
|
||||
|
||||
rdp_frame->damage_region = damage_region;
|
||||
grd_encode_context_set_damage_region (rdp_frame->encode_context,
|
||||
damage_region);
|
||||
|
||||
if (!grd_rdp_render_context_must_delay_view_finalization (render_context))
|
||||
finalize_view (rdp_frame);
|
||||
}
|
||||
|
||||
void
|
||||
grd_rdp_frame_set_bitstreams (GrdRdpFrame *rdp_frame,
|
||||
GList *bitstreams)
|
||||
{
|
||||
rdp_frame->bitstreams = bitstreams;
|
||||
}
|
||||
|
||||
void
|
||||
grd_rdp_frame_notify_picked_up (GrdRdpFrame *rdp_frame)
|
||||
{
|
||||
rdp_frame->frame_picked_up (rdp_frame, rdp_frame->callback_user_data);
|
||||
}
|
||||
|
||||
void
|
||||
grd_rdp_frame_notify_frame_submission (GrdRdpFrame *rdp_frame)
|
||||
{
|
||||
rdp_frame->frame_submitted (rdp_frame, rdp_frame->callback_user_data);
|
||||
}
|
||||
|
||||
GrdImageView *
|
||||
grd_rdp_frame_pop_image_view (GrdRdpFrame *rdp_frame)
|
||||
{
|
||||
return g_queue_pop_head (rdp_frame->unused_image_views);
|
||||
}
|
||||
|
||||
static void
|
||||
set_view_type (GrdRdpFrame *rdp_frame,
|
||||
gboolean frame_upgrade)
|
||||
{
|
||||
GrdRdpRenderContext *render_context = rdp_frame->render_context;
|
||||
GrdRdpCodec codec = grd_rdp_render_context_get_codec (render_context);
|
||||
|
||||
switch (codec)
|
||||
{
|
||||
case GRD_RDP_CODEC_CAPROGRESSIVE:
|
||||
case GRD_RDP_CODEC_AVC420:
|
||||
rdp_frame->view_type = GRD_RDP_FRAME_VIEW_TYPE_MAIN;
|
||||
break;
|
||||
case GRD_RDP_CODEC_AVC444v2:
|
||||
rdp_frame->view_type =
|
||||
frame_upgrade ? GRD_RDP_FRAME_VIEW_TYPE_AUX
|
||||
: GRD_RDP_FRAME_VIEW_TYPE_DUAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
get_n_required_image_views (GrdRdpFrame *rdp_frame)
|
||||
{
|
||||
GrdRdpRenderContext *render_context = rdp_frame->render_context;
|
||||
GrdRdpCodec codec = grd_rdp_render_context_get_codec (render_context);
|
||||
|
||||
switch (codec)
|
||||
{
|
||||
case GRD_RDP_CODEC_CAPROGRESSIVE:
|
||||
return 1;
|
||||
case GRD_RDP_CODEC_AVC420:
|
||||
case GRD_RDP_CODEC_AVC444v2:
|
||||
return 2;
|
||||
}
|
||||
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
get_n_image_views_to_be_encoded (GrdRdpFrame *rdp_frame)
|
||||
{
|
||||
switch (grd_rdp_frame_get_avc_view_type (rdp_frame))
|
||||
{
|
||||
case GRD_RDP_FRAME_VIEW_TYPE_DUAL:
|
||||
return 2;
|
||||
case GRD_RDP_FRAME_VIEW_TYPE_MAIN:
|
||||
case GRD_RDP_FRAME_VIEW_TYPE_AUX:
|
||||
return 1;
|
||||
}
|
||||
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
static void
|
||||
acquire_image_views (GrdRdpFrame *rdp_frame)
|
||||
{
|
||||
uint32_t n_image_views = get_n_required_image_views (rdp_frame);
|
||||
uint32_t n_image_views_to_be_encoded =
|
||||
get_n_image_views_to_be_encoded (rdp_frame);
|
||||
uint32_t i;
|
||||
|
||||
g_assert (n_image_views_to_be_encoded <= n_image_views);
|
||||
|
||||
for (i = 0; i < n_image_views; ++i)
|
||||
{
|
||||
GrdRdpRenderContext *render_context = rdp_frame->render_context;
|
||||
GrdImageView *image_view;
|
||||
|
||||
image_view = grd_rdp_render_context_acquire_image_view (render_context);
|
||||
rdp_frame->acquired_image_views =
|
||||
g_list_append (rdp_frame->acquired_image_views, image_view);
|
||||
|
||||
if (i < n_image_views_to_be_encoded)
|
||||
g_queue_push_tail (rdp_frame->unused_image_views, image_view);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
prepare_new_frame (GrdRdpFrame *rdp_frame)
|
||||
{
|
||||
rdp_frame->pending_view_finalization = TRUE;
|
||||
|
||||
set_view_type (rdp_frame, FALSE);
|
||||
acquire_image_views (rdp_frame);
|
||||
}
|
||||
|
||||
static void
|
||||
prepare_frame_upgrade (GrdRdpFrame *rdp_frame)
|
||||
{
|
||||
GrdRdpRenderContext *render_context = rdp_frame->render_context;
|
||||
cairo_region_t *damage_region = NULL;
|
||||
GrdImageView *image_view = NULL;
|
||||
|
||||
set_view_type (rdp_frame, TRUE);
|
||||
|
||||
grd_rdp_render_context_fetch_progressive_render_state (render_context,
|
||||
&image_view,
|
||||
&damage_region);
|
||||
g_assert (image_view);
|
||||
g_assert (damage_region);
|
||||
|
||||
rdp_frame->acquired_image_views =
|
||||
g_list_append (rdp_frame->acquired_image_views, image_view);
|
||||
g_queue_push_tail (rdp_frame->unused_image_views, image_view);
|
||||
|
||||
rdp_frame->damage_region = damage_region;
|
||||
}
|
||||
|
||||
GrdRdpFrame *
|
||||
grd_rdp_frame_new (GrdRdpRenderContext *render_context,
|
||||
GrdRdpBuffer *src_buffer_new,
|
||||
GrdRdpBuffer *src_buffer_old,
|
||||
GrdRdpFrameCallback frame_picked_up,
|
||||
GrdRdpFrameCallback view_finalized,
|
||||
GrdRdpFrameCallback frame_submitted,
|
||||
GrdRdpFrameCallback frame_finalized,
|
||||
gpointer callback_user_data,
|
||||
GDestroyNotify user_data_destroy)
|
||||
{
|
||||
GrdRdpFrame *rdp_frame;
|
||||
|
||||
rdp_frame = g_new0 (GrdRdpFrame, 1);
|
||||
rdp_frame->render_context = render_context;
|
||||
rdp_frame->src_buffer_new = src_buffer_new;
|
||||
rdp_frame->src_buffer_old = src_buffer_old;
|
||||
|
||||
rdp_frame->frame_picked_up = frame_picked_up;
|
||||
rdp_frame->view_finalized = view_finalized;
|
||||
rdp_frame->frame_submitted = frame_submitted;
|
||||
rdp_frame->frame_finalized = frame_finalized;
|
||||
rdp_frame->callback_user_data = callback_user_data;
|
||||
rdp_frame->user_data_destroy = user_data_destroy;
|
||||
|
||||
rdp_frame->encode_context = grd_encode_context_new ();
|
||||
rdp_frame->unused_image_views = g_queue_new ();
|
||||
|
||||
if (src_buffer_new)
|
||||
prepare_new_frame (rdp_frame);
|
||||
else
|
||||
prepare_frame_upgrade (rdp_frame);
|
||||
|
||||
return rdp_frame;
|
||||
}
|
||||
|
||||
static void
|
||||
release_image_views (GrdRdpFrame *rdp_frame)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
for (l = rdp_frame->acquired_image_views; l; l = l->next)
|
||||
{
|
||||
GrdImageView *image_view = l->data;
|
||||
|
||||
grd_rdp_render_context_release_image_view (rdp_frame->render_context,
|
||||
image_view);
|
||||
}
|
||||
g_clear_pointer (&rdp_frame->acquired_image_views, g_list_free);
|
||||
}
|
||||
|
||||
void
|
||||
grd_rdp_frame_free (GrdRdpFrame *rdp_frame)
|
||||
{
|
||||
g_assert (!rdp_frame->bitstreams);
|
||||
g_assert (rdp_frame->renderer);
|
||||
|
||||
if (rdp_frame->pending_view_finalization)
|
||||
finalize_view (rdp_frame);
|
||||
|
||||
g_clear_pointer (&rdp_frame->encode_context, grd_encode_context_free);
|
||||
g_clear_pointer (&rdp_frame->damage_region, cairo_region_destroy);
|
||||
|
||||
g_clear_pointer (&rdp_frame->unused_image_views, g_queue_free);
|
||||
release_image_views (rdp_frame);
|
||||
|
||||
rdp_frame->frame_finalized (rdp_frame, rdp_frame->callback_user_data);
|
||||
g_clear_pointer (&rdp_frame->callback_user_data,
|
||||
rdp_frame->user_data_destroy);
|
||||
|
||||
g_free (rdp_frame);
|
||||
}
|
||||
Reference in New Issue
Block a user