xfreerdp: initial RemoteApp support with --gdi hw (much faster)

This commit is contained in:
Marc-André Moreau 2011-09-23 00:06:39 -04:00
parent 3869228349
commit c003c5c038
8 changed files with 239 additions and 67 deletions

View File

@ -197,7 +197,7 @@ Pixmap xf_bitmap_new(xfInfo* xfi, int width, int height, int bpp, uint8* data)
uint8* cdata;
XImage* image;
bitmap = XCreatePixmap(xfi->display, xfi->window->handle, width, height, xfi->bpp);
bitmap = XCreatePixmap(xfi->display, xfi->drawable, width, height, xfi->bpp);
cdata = freerdp_image_convert(data, NULL, width, height, bpp, xfi->bpp, xfi->clrconv);
@ -221,7 +221,7 @@ Pixmap xf_mono_bitmap_new(xfInfo* xfi, int width, int height, uint8* data)
scanline = (width + 7) / 8;
bitmap = XCreatePixmap(xfi->display, xfi->window->handle, width, height, 1);
bitmap = XCreatePixmap(xfi->display, xfi->drawable, width, height, 1);
image = XCreateImage(xfi->display, xfi->visual, 1,
ZPixmap, 0, (char*) data, width, height, 8, scanline);
@ -240,7 +240,7 @@ Pixmap xf_glyph_new(xfInfo* xfi, int width, int height, uint8* data)
scanline = (width + 7) / 8;
bitmap = XCreatePixmap(xfi->display, xfi->window->handle, width, height, 1);
bitmap = XCreatePixmap(xfi->display, xfi->drawable, width, height, 1);
image = XCreateImage(xfi->display, xfi->visual, 1,
ZPixmap, 0, (char*) data, width, height, 8, scanline);
@ -280,7 +280,11 @@ void xf_gdi_bitmap_update(rdpUpdate* update, BITMAP_UPDATE* bitmap)
h = bmp->bottom - bmp->top + 1;
XPutImage(xfi->display, xfi->primary, xfi->gc, image, 0, 0, x, y, w, h);
XCopyArea(xfi->display, xfi->primary, xfi->window->handle, xfi->gc, x, y, w, h, x, y);
if (xfi->remote_app != True)
XCopyArea(xfi->display, xfi->primary, xfi->drawable, xfi->gc, x, y, w, h, x, y);
gdi_InvalidateRegion(xfi->hdc, x, y, w, h);
}
}
@ -321,9 +325,14 @@ void xf_gdi_dstblt(rdpUpdate* update, DSTBLT_ORDER* dstblt)
if (xfi->drawing == xfi->primary)
{
XFillRectangle(xfi->display, xfi->window->handle, xfi->gc,
if (xfi->remote_app != True)
{
XFillRectangle(xfi->display, xfi->drawable, xfi->gc,
dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth, dstblt->nHeight);
}
gdi_InvalidateRegion(xfi->hdc, dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth, dstblt->nHeight);
}
}
void xf_gdi_patblt(rdpUpdate* update, PATBLT_ORDER* patblt)
@ -392,9 +401,15 @@ void xf_gdi_patblt(rdpUpdate* update, PATBLT_ORDER* patblt)
if (xfi->drawing == xfi->primary)
{
XSetFunction(xfi->display, xfi->gc, GXcopy);
XCopyArea(xfi->display, xfi->primary, xfi->window->handle, xfi->gc, patblt->nLeftRect, patblt->nTopRect,
if (xfi->remote_app != True)
{
XCopyArea(xfi->display, xfi->primary, xfi->drawable, xfi->gc, patblt->nLeftRect, patblt->nTopRect,
patblt->nWidth, patblt->nHeight, patblt->nLeftRect, patblt->nTopRect);
}
gdi_InvalidateRegion(xfi->hdc, patblt->nLeftRect, patblt->nTopRect, patblt->nWidth, patblt->nHeight);
}
}
void xf_gdi_scrblt(rdpUpdate* update, SCRBLT_ORDER* scrblt)
@ -402,25 +417,31 @@ void xf_gdi_scrblt(rdpUpdate* update, SCRBLT_ORDER* scrblt)
xfInfo* xfi = GET_XFI(update);
xf_set_rop3(xfi, gdi_rop3_code(scrblt->bRop));
XCopyArea(xfi->display, xfi->primary, xfi->drawing, xfi->gc, scrblt->nXSrc, scrblt->nYSrc,
scrblt->nWidth, scrblt->nHeight, scrblt->nLeftRect, scrblt->nTopRect);
if (xfi->drawing == xfi->primary)
{
if (xfi->remote_app != True)
{
if (xfi->unobscured)
{
XCopyArea(xfi->display, xfi->window->handle, xfi->window->handle, xfi->gc,
XCopyArea(xfi->display, xfi->drawable, xfi->drawable, xfi->gc,
scrblt->nXSrc, scrblt->nYSrc, scrblt->nWidth, scrblt->nHeight,
scrblt->nLeftRect, scrblt->nTopRect);
}
else
{
XSetFunction(xfi->display, xfi->gc, GXcopy);
XCopyArea(xfi->display, xfi->primary, xfi->window->handle, xfi->gc,
XCopyArea(xfi->display, xfi->primary, xfi->drawable, xfi->gc,
scrblt->nLeftRect, scrblt->nTopRect, scrblt->nWidth, scrblt->nHeight,
scrblt->nLeftRect, scrblt->nTopRect);
}
}
gdi_InvalidateRegion(xfi->hdc, scrblt->nXSrc, scrblt->nYSrc, scrblt->nWidth, scrblt->nHeight);
}
}
void xf_gdi_opaque_rect(rdpUpdate* update, OPAQUE_RECT_ORDER* opaque_rect)
@ -439,9 +460,15 @@ void xf_gdi_opaque_rect(rdpUpdate* update, OPAQUE_RECT_ORDER* opaque_rect)
if (xfi->drawing == xfi->primary)
{
XFillRectangle(xfi->display, xfi->window->handle, xfi->gc,
if (xfi->remote_app != True)
{
XFillRectangle(xfi->display, xfi->drawable, xfi->gc,
opaque_rect->nLeftRect, opaque_rect->nTopRect, opaque_rect->nWidth, opaque_rect->nHeight);
}
gdi_InvalidateRegion(xfi->hdc, opaque_rect->nLeftRect, opaque_rect->nTopRect,
opaque_rect->nWidth, opaque_rect->nHeight);
}
}
void xf_gdi_multi_opaque_rect(rdpUpdate* update, MULTI_OPAQUE_RECT_ORDER* multi_opaque_rect)
@ -467,9 +494,14 @@ void xf_gdi_multi_opaque_rect(rdpUpdate* update, MULTI_OPAQUE_RECT_ORDER* multi_
if (xfi->drawing == xfi->primary)
{
XFillRectangle(xfi->display, xfi->window->handle, xfi->gc,
if (xfi->remote_app != True)
{
XFillRectangle(xfi->display, xfi->drawable, xfi->gc,
rectangle->left, rectangle->top, rectangle->width, rectangle->height);
}
gdi_InvalidateRegion(xfi->hdc, rectangle->left, rectangle->top, rectangle->width, rectangle->height);
}
}
}
@ -489,8 +521,24 @@ void xf_gdi_line_to(rdpUpdate* update, LINE_TO_ORDER* line_to)
if (xfi->drawing == xfi->primary)
{
XDrawLine(xfi->display, xfi->window->handle, xfi->gc,
if (xfi->remote_app != True)
{
int width, height;
XDrawLine(xfi->display, xfi->drawable, xfi->gc,
line_to->nXStart, line_to->nYStart, line_to->nXEnd, line_to->nYEnd);
width = line_to->nXStart - line_to->nXEnd;
height = line_to->nYStart - line_to->nYEnd;
if (width < 0)
width *= (-1);
if (height < 0)
height *= (-1);
gdi_InvalidateRegion(xfi->hdc, line_to->nXStart, line_to->nYStart, width, height);
}
}
}
@ -519,7 +567,10 @@ void xf_gdi_polyline(rdpUpdate* update, POLYLINE_ORDER* polyline)
if (xfi->drawing == xfi->primary)
{
XDrawLines(xfi->display, xfi->window->handle, xfi->gc, points, polyline->numPoints, CoordModePrevious);
if (xfi->remote_app != True)
{
XDrawLines(xfi->display, xfi->drawable, xfi->gc, points, polyline->numPoints, CoordModePrevious);
}
}
xfree(points);
@ -529,6 +580,7 @@ void xf_gdi_fast_index(rdpUpdate* update, FAST_INDEX_ORDER* fast_index)
{
int i, j;
int x, y;
int w, h;
Pixmap bmp;
Pixmap* bmps;
uint32 fgcolor;
@ -538,9 +590,6 @@ void xf_gdi_fast_index(rdpUpdate* update, FAST_INDEX_ORDER* fast_index)
GLYPH_FRAGMENT* fragment;
xfInfo* xfi = GET_XFI(update);
x = fast_index->bkLeft;
y = fast_index->y;
fgcolor = freerdp_color_convert(fast_index->foreColor, xfi->srcBpp, 32, xfi->clrconv);
bgcolor = freerdp_color_convert(fast_index->backColor, xfi->srcBpp, 32, xfi->clrconv);
@ -552,16 +601,27 @@ void xf_gdi_fast_index(rdpUpdate* update, FAST_INDEX_ORDER* fast_index)
{
XSetFillStyle(xfi->display, xfi->gc, FillSolid);
XFillRectangle(xfi->display, xfi->drawing, xfi->gc, fast_index->opLeft, fast_index->opTop,
fast_index->opRight - fast_index->opLeft + 1, fast_index->opBottom - fast_index->opTop + 1);
x = fast_index->opLeft;
y = fast_index->opTop;
w = fast_index->opRight - fast_index->opLeft + 1;
h = fast_index->opBottom - fast_index->opTop + 1;
XFillRectangle(xfi->display, xfi->drawing, xfi->gc, x, y, w, h);
if (xfi->drawing == xfi->primary)
{
XFillRectangle(xfi->display, xfi->window->handle, xfi->gc, fast_index->opLeft, fast_index->opTop,
fast_index->opRight - fast_index->opLeft + 1, fast_index->opBottom - fast_index->opTop + 1);
if (xfi->remote_app != True)
{
XFillRectangle(xfi->display, xfi->drawable, xfi->gc, x, y, w, h);
}
gdi_InvalidateRegion(xfi->hdc, x, y, w, h);
}
}
x = fast_index->bkLeft;
y = fast_index->y;
XSetFillStyle(xfi->display, xfi->gc, FillStippled);
for (i = 0; i < fast_index->nfragments; i++)
@ -630,12 +690,19 @@ void xf_gdi_fast_index(rdpUpdate* update, FAST_INDEX_ORDER* fast_index)
if (xfi->drawing == xfi->primary)
{
XCopyArea(xfi->display, xfi->primary, xfi->window->handle, xfi->gc,
if (xfi->remote_app != True)
{
XCopyArea(xfi->display, xfi->primary, xfi->drawable, xfi->gc,
fast_index->bkLeft, fast_index->bkTop,
fast_index->bkRight - fast_index->bkLeft + 1,
fast_index->bkBottom - fast_index->bkTop + 1,
fast_index->bkLeft, fast_index->bkTop);
}
gdi_InvalidateRegion(xfi->hdc, fast_index->bkLeft, fast_index->bkTop,
fast_index->bkRight - fast_index->bkLeft + 1,
fast_index->bkBottom - fast_index->bkTop + 1);
}
}
void xf_gdi_create_offscreen_bitmap(rdpUpdate* update, CREATE_OFFSCREEN_BITMAP_ORDER* create_offscreen_bitmap)
@ -741,10 +808,15 @@ void xf_gdi_surface_bits(rdpUpdate* update, SURFACE_BITS_COMMAND* surface_bits_c
tx = message->rects[i].x + surface_bits_command->destLeft;
ty = message->rects[i].y + surface_bits_command->destTop;
XCopyArea(xfi->display, xfi->primary, xfi->window->handle, xfi->gc,
if (xfi->remote_app != True)
{
XCopyArea(xfi->display, xfi->primary, xfi->drawable, xfi->gc,
tx, ty, message->rects[i].width, message->rects[i].height, tx, ty);
}
gdi_InvalidateRegion(xfi->hdc, tx, ty, message->rects[i].width, message->rects[i].height);
}
XSetClipMask(xfi->display, xfi->gc, None);
rfx_message_free(context, message);
}
@ -766,10 +838,16 @@ void xf_gdi_surface_bits(rdpUpdate* update, SURFACE_BITS_COMMAND* surface_bits_c
surface_bits_command->destLeft, surface_bits_command->destTop,
surface_bits_command->width, surface_bits_command->height);
if (xfi->remote_app != True)
{
XCopyArea(xfi->display, xfi->primary, xfi->window->handle, xfi->gc,
surface_bits_command->destLeft, surface_bits_command->destTop,
surface_bits_command->width, surface_bits_command->height,
surface_bits_command->destLeft, surface_bits_command->destTop);
}
gdi_InvalidateRegion(xfi->hdc, surface_bits_command->destLeft, surface_bits_command->destTop,
surface_bits_command->width, surface_bits_command->height);
XSetClipMask(xfi->display, xfi->gc, None);
}

View File

@ -568,8 +568,11 @@ void xf_UpdateWindowArea(xfInfo* xfi, xfWindow* window, int x, int y, int width,
if (ay + height > wnd->windowOffsetY + wnd->windowHeight)
height = (wnd->windowOffsetY + wnd->windowHeight - 1) - ay;
if (xfi->sw_gdi)
{
XPutImage(xfi->display, xfi->primary, window->gc, xfi->image,
ax, ay, ax, ay, width, height);
}
XCopyArea(xfi->display, xfi->primary, window->handle, window->gc,
ax, ay, width, height, x, y);

View File

@ -63,7 +63,7 @@ struct thread_data
freerdp* instance;
};
void xf_begin_paint(rdpUpdate* update)
void xf_sw_begin_paint(rdpUpdate* update)
{
GDI* gdi;
gdi = GET_GDI(update);
@ -71,7 +71,7 @@ void xf_begin_paint(rdpUpdate* update)
gdi->primary->hdc->hwnd->ninvalid = 0;
}
void xf_end_paint(rdpUpdate* update)
void xf_sw_end_paint(rdpUpdate* update)
{
GDI* gdi;
xfInfo* xfi;
@ -136,18 +136,70 @@ void xf_end_paint(rdpUpdate* update)
}
}
void xf_desktop_resize(rdpUpdate* update)
void xf_sw_desktop_resize(rdpUpdate* update)
{
xfInfo* xfi;
rdpSettings* settings;
xfi = GET_XFI(update);
settings = xfi->instance->settings;
if (xfi->fullscreen != True)
{
GDI* gdi = GET_GDI(update);
gdi_resize(gdi, xfi->width, xfi->height);
if (xfi->image)
{
xfi->image->data = NULL;
XDestroyImage(xfi->image);
xfi->image = XCreateImage(xfi->display, xfi->visual, xfi->depth, ZPixmap, 0,
(char*) gdi->primary_buffer, gdi->width, gdi->height, xfi->scanline_pad, 0);
}
}
}
void xf_hw_begin_paint(rdpUpdate* update)
{
xfInfo* xfi;
xfi = GET_XFI(update);
xfi->hdc->hwnd->invalid->null = 1;
xfi->hdc->hwnd->ninvalid = 0;
}
void xf_hw_end_paint(rdpUpdate* update)
{
xfInfo* xfi;
sint32 x, y;
uint32 w, h;
xfi = GET_XFI(update);
if (xfi->remote_app)
{
if (xfi->hdc->hwnd->invalid->null)
return;
x = xfi->hdc->hwnd->invalid->x;
y = xfi->hdc->hwnd->invalid->y;
w = xfi->hdc->hwnd->invalid->w;
h = xfi->hdc->hwnd->invalid->h;
xf_rail_paint(xfi, update->rail, x, y, x + w - 1, y + h - 1);
}
}
void xf_hw_desktop_resize(rdpUpdate* update)
{
GDI* gdi;
xfInfo* xfi;
boolean same;
rdpSettings* settings;
xfi = GET_XFI(update);
gdi = GET_GDI(update);
settings = xfi->instance->settings;
if (!xfi->fullscreen)
if (xfi->fullscreen != True)
{
xfi->width = settings->width;
xfi->height = settings->height;
@ -157,24 +209,16 @@ void xf_desktop_resize(rdpUpdate* update)
if (xfi->primary)
{
same = (xfi->primary == xfi->drawing ? True : False);
same = (xfi->primary == xfi->drawing) ? True : False;
XFreePixmap(xfi->display, xfi->primary);
xfi->primary = XCreatePixmap(xfi->display, DefaultRootWindow(xfi->display),
xfi->primary = XCreatePixmap(xfi->display, xfi->drawable,
xfi->width, xfi->height, xfi->depth);
if (same)
xfi->drawing = xfi->primary;
}
if (gdi)
gdi_resize(gdi, xfi->width, xfi->height);
if (gdi && xfi->image)
{
xfi->image->data = NULL;
XDestroyImage(xfi->image);
xfi->image = XCreateImage(xfi->display, xfi->visual, xfi->depth, ZPixmap, 0,
(char*) gdi->primary_buffer, gdi->width, gdi->height, xfi->scanline_pad, 0);
}
}
}
@ -372,6 +416,7 @@ boolean xf_pre_connect(freerdp* instance)
xfi->remote_app = settings->remote_app;
xfi->fullscreen = settings->fullscreen;
xfi->fullscreen_toggle = xfi->fullscreen;
xfi->sw_gdi = settings->sw_gdi;
xf_detect_monitors(xfi, settings);
@ -380,7 +425,6 @@ boolean xf_pre_connect(freerdp* instance)
boolean xf_post_connect(freerdp* instance)
{
GDI* gdi;
xfInfo* xfi;
XEvent xevent;
XGCValues gcv;
@ -391,14 +435,36 @@ boolean xf_post_connect(freerdp* instance)
if (xf_get_pixmap_info(xfi) != True)
return False;
if (xfi->sw_gdi)
{
GDI* gdi;
gdi_init(instance, CLRCONV_ALPHA | CLRBUF_32BPP);
gdi = GET_GDI(instance->update);
if (instance->settings->sw_gdi != True)
xfi->primary_buffer = gdi->primary_buffer;
}
else
{
xfi->srcBpp = instance->settings->color_depth;
xf_gdi_register_update_callbacks(instance->update);
xfi->hdc = gdi_GetDC();
xfi->hdc->bitsPerPixel = xfi->bpp;
xfi->hdc->bytesPerPixel = xfi->bpp / 8;
xfi->hdc->alpha = xfi->clrconv->alpha;
xfi->hdc->invert = xfi->clrconv->invert;
xfi->hdc->rgb555 = xfi->clrconv->rgb555;
xfi->hdc->hwnd = (HGDI_WND) malloc(sizeof(GDI_WND));
xfi->hdc->hwnd->invalid = gdi_CreateRectRgn(0, 0, 0, 0);
xfi->hdc->hwnd->invalid->null = 1;
xfi->hdc->hwnd->count = 32;
xfi->hdc->hwnd->cinvalid = (HGDI_RGN) malloc(sizeof(GDI_RGN) * xfi->hdc->hwnd->count);
xfi->hdc->hwnd->ninvalid = 0;
xfi->primary_buffer = (uint8*) xzalloc(xfi->width * xfi->height * xfi->bpp);
if (instance->settings->rfx_codec)
xfi->rfx_context = (void*) rfx_context_new();
}
@ -434,6 +500,11 @@ boolean xf_post_connect(freerdp* instance)
xfi->unobscured = (xevent.xvisibility.state == VisibilityUnobscured);
XSetWMProtocols(xfi->display, xfi->window->handle, &(xfi->WM_DELETE_WINDOW), 1);
xfi->drawable = xfi->window->handle;
}
else
{
xfi->drawable = DefaultRootWindow(xfi->display);
}
memset(&gcv, 0, sizeof(gcv));
@ -450,13 +521,22 @@ boolean xf_post_connect(freerdp* instance)
XFillRectangle(xfi->display, xfi->primary, xfi->gc, 0, 0, xfi->width, xfi->height);
xfi->image = XCreateImage(xfi->display, xfi->visual, xfi->depth, ZPixmap, 0,
(char*) gdi->primary_buffer, gdi->width, gdi->height, xfi->scanline_pad, 0);
(char*) xfi->primary_buffer, xfi->width, xfi->height, xfi->scanline_pad, 0);
xfi->bmp_codec_none = (uint8*) xmalloc(64 * 64 * 4);
instance->update->BeginPaint = xf_begin_paint;
instance->update->EndPaint = xf_end_paint;
instance->update->DesktopResize = xf_desktop_resize;
if (xfi->sw_gdi)
{
instance->update->BeginPaint = xf_sw_begin_paint;
instance->update->EndPaint = xf_sw_end_paint;
instance->update->DesktopResize = xf_sw_desktop_resize;
}
else
{
instance->update->BeginPaint = xf_hw_begin_paint;
instance->update->EndPaint = xf_hw_end_paint;
instance->update->DesktopResize = xf_hw_desktop_resize;
}
xfi->rail = rail_new(instance->settings);
instance->update->rail = (void*) xfi->rail;

View File

@ -25,6 +25,8 @@
#include <freerdp/freerdp.h>
#include <freerdp/chanman/chanman.h>
#include <freerdp/gdi/gdi.h>
#include <freerdp/gdi/dc.h>
#include <freerdp/gdi/region.h>
#include <freerdp/rail/rail.h>
#include <freerdp/cache/cache.h>
@ -64,6 +66,7 @@ struct xf_info
Pixmap drawing;
Visual* visual;
Display* display;
Drawable drawable;
Pixmap bitmap_mono;
Colormap colormap;
int screen_number;
@ -81,6 +84,10 @@ struct xf_info
rdpRail* rail;
rdpCache* cache;
HGDI_DC hdc;
boolean sw_gdi;
uint8* primary_buffer;
boolean focused;
boolean mouse_active;
boolean mouse_motion;
@ -119,8 +126,6 @@ struct xf_info
void xf_toggle_fullscreen(xfInfo* xfi);
boolean xf_post_connect(freerdp* instance);
//#define WITH_DEBUG_X11
#ifdef WITH_DEBUG_X11
#define DEBUG_X11(fmt, ...) DEBUG_CLASS(X11, fmt, ## __VA_ARGS__)
#else

View File

@ -278,6 +278,7 @@ struct rdp_settings
boolean sound_beeps;
boolean color_pointer;
boolean smooth_fonts;
uint16 pointer_cache_size;
boolean fastpath_input;

View File

@ -237,6 +237,4 @@ void update_read_draw_gdiplus_cache_first_order(STREAM* s, DRAW_GDIPLUS_CACHE_FI
void update_read_draw_gdiplus_cache_next_order(STREAM* s, DRAW_GDIPLUS_CACHE_NEXT_ORDER* draw_gdiplus_cache_next);
void update_read_draw_gdiplus_cache_end_order(STREAM* s, DRAW_GDIPLUS_CACHE_END_ORDER* draw_gdiplus_cache_end);
//#define WITH_DEBUG_ORDERS 1
#endif /* __ORDERS_H */

View File

@ -995,7 +995,7 @@ void gdi_register_update_callbacks(rdpUpdate* update)
update->SurfaceBits = gdi_surface_bits;
}
static void gdi_init_primary(GDI* gdi)
void gdi_init_primary(GDI* gdi)
{
gdi->primary = gdi_bitmap_new(gdi, gdi->width, gdi->height, gdi->dstBpp, NULL);
gdi->primary_buffer = gdi->primary->bitmap->data;

View File

@ -304,6 +304,10 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv,
settings->play_rfx_file = xstrdup(argv[index]);
settings->play_rfx = True;
}
else if (strcmp("--fonts", argv[index]) == 0)
{
settings->smooth_fonts = True;
}
else if (strcmp("--no-motion", argv[index]) == 0)
{
settings->mouse_motion = False;
@ -502,6 +506,9 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv,
followed will be parsed for the next session. */
index++;
if (settings->smooth_fonts)
settings->performance_flags |= PERF_ENABLE_FONT_SMOOTHING;
return index;
}
else