Changeset 8aef01c in mainline for uspace/srv/hid/display/display.c


Ignore:
Timestamp:
2020-06-07T10:18:14Z (5 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
a65b0c8
Parents:
6301a24f
git-author:
Jiri Svoboda <jiri@…> (2020-06-07 10:11:32)
git-committer:
Jiri Svoboda <jiri@…> (2020-06-07 10:18:14)
Message:

Configurable display double-buffering

On by default (since turning off creates flicker in the absence of
front-to-back rendering). This is the quick and dirty way: display
server renders locally to a bitmap (using mem GC) and renders the
bitmap when ready.

The more sophisticated way would be to implement buffering in the
display device. That would require, however, enhancing the protocols
to communicate frame boundaries.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/hid/display/display.c

    r6301a24f r8aef01c  
    3535
    3636#include <errno.h>
     37#include <gfx/bitmap.h>
    3738#include <gfx/context.h>
    3839#include <gfx/render.h>
    3940#include <io/log.h>
     41#include <memgfx/memgc.h>
    4042#include <stdlib.h>
    4143#include "client.h"
     
    4648#include "display.h"
    4749
     50static gfx_context_t *ds_display_get_unbuf_gc(ds_display_t *);
     51static void ds_display_update_cb(void *, gfx_rect_t *);
     52
    4853/** Create display.
    4954 *
    5055 * @param gc Graphics context for displaying output
     56 * @param flags Display flags
    5157 * @param rdisp Place to store pointer to new display.
    5258 * @return EOK on success, ENOMEM if out of memory
    5359 */
    54 errno_t ds_display_create(gfx_context_t *gc, ds_display_t **rdisp)
     60errno_t ds_display_create(gfx_context_t *gc, ds_display_flags_t flags,
     61    ds_display_t **rdisp)
    5562{
    5663        ds_display_t *disp;
     
    8693        list_initialize(&disp->seats);
    8794        list_initialize(&disp->windows);
     95        disp->flags = flags;
    8896        *rdisp = disp;
    8997        return EOK;
     
    423431}
    424432
     433/** Allocate back buffer for display.
     434 *
     435 * @param disp Display
     436 * @return EOK on success or if no back buffer is required, otherwise
     437 *         an error code.
     438 */
     439static errno_t ds_display_alloc_backbuf(ds_display_t *disp)
     440{
     441        gfx_context_t *ugc;
     442        gfx_bitmap_params_t params;
     443        gfx_bitmap_alloc_t alloc;
     444        errno_t rc;
     445
     446        /* Allocate backbuffer */
     447        if ((disp->flags & df_disp_double_buf) == 0) {
     448                /* Not double buffering. Nothing to do. */
     449                return EOK;
     450        }
     451
     452        ugc = ds_display_get_unbuf_gc(disp);
     453
     454        gfx_bitmap_params_init(&params);
     455        params.rect = disp->rect;
     456
     457        rc = gfx_bitmap_create(ugc, &params, NULL,
     458            &disp->backbuf);
     459        if (rc != EOK)
     460                goto error;
     461
     462        rc = gfx_bitmap_get_alloc(disp->backbuf, &alloc);
     463        if (rc != EOK)
     464                goto error;
     465
     466        rc = mem_gc_create(&disp->rect, &alloc,
     467            ds_display_update_cb, (void *) disp, &disp->bbgc);
     468        if (rc != EOK)
     469                goto error;
     470
     471        disp->dirty_rect.p0.x = 0;
     472        disp->dirty_rect.p0.y = 0;
     473        disp->dirty_rect.p1.x = 0;
     474        disp->dirty_rect.p1.y = 0;
     475
     476        return EOK;
     477error:
     478        if (disp->backbuf != NULL) {
     479                gfx_bitmap_destroy(disp->backbuf);
     480                disp->backbuf = NULL;
     481        }
     482
     483        return rc;
     484}
     485
    425486/** Add display device to display.
    426487 *
    427488 * @param disp Display
    428489 * @param ddev Display device
    429  */
    430 void ds_display_add_ddev(ds_display_t *disp, ds_ddev_t *ddev)
    431 {
     490 * @return EOK on success, or an error code
     491 */
     492errno_t ds_display_add_ddev(ds_display_t *disp, ds_ddev_t *ddev)
     493{
     494        errno_t rc;
     495
    432496        assert(ddev->display == NULL);
    433497        assert(!link_used(&ddev->lddevs));
    434498
    435         /* Set display dimensions to dimensions of first display device */
    436         if (gfx_rect_is_empty(&disp->rect))
    437                 disp->rect = ddev->info.rect;
    438 
    439499        ddev->display = disp;
    440500        list_append(&ddev->lddevs, &disp->ddevs);
     501
     502        /* First display device */
     503        if (gfx_rect_is_empty(&disp->rect)) {
     504                /* Set screen dimensions */
     505                disp->rect = ddev->info.rect;
     506
     507                /* Allocate backbuffer */
     508                rc = ds_display_alloc_backbuf(disp);
     509                if (rc != EOK)
     510                        goto error;
     511        }
     512
     513        return EOK;
     514error:
     515        disp->rect.p0.x = 0;
     516        disp->rect.p0.y = 0;
     517        disp->rect.p1.x = 0;
     518        disp->rect.p1.y = 0;
     519        list_remove(&ddev->lddevs);
     520        return rc;
    441521}
    442522
     
    506586
    507587// XXX
    508 gfx_context_t *ds_display_get_gc(ds_display_t *display)
     588static gfx_context_t *ds_display_get_unbuf_gc(ds_display_t *display)
    509589{
    510590        ds_ddev_t *ddev;
     
    515595
    516596        return ddev->gc;
     597}
     598
     599// XXX
     600gfx_context_t *ds_display_get_gc(ds_display_t *display)
     601{
     602        if ((display->flags & df_disp_double_buf) != 0)
     603                return mem_gc_get_ctx(display->bbgc);
     604        else
     605                return ds_display_get_unbuf_gc(display);
    517606}
    518607
     
    542631
    543632        return gfx_fill_rect(gc, &crect);
     633}
     634
     635/** Update front buffer from back buffer.
     636 *
     637 * If the display is not double-buffered, no action is taken.
     638 *
     639 * @param disp Display
     640 * @return EOK on success, or an error code
     641 */
     642static errno_t ds_display_update(ds_display_t *disp)
     643{
     644        errno_t rc;
     645
     646        if (disp->backbuf == NULL) {
     647                /* Not double-buffered, nothing to do. */
     648                return EOK;
     649        }
     650
     651        rc = gfx_bitmap_render(disp->backbuf, &disp->dirty_rect, NULL);
     652        if (rc != EOK)
     653                return rc;
     654
     655        disp->dirty_rect.p0.x = 0;
     656        disp->dirty_rect.p0.y = 0;
     657        disp->dirty_rect.p1.x = 0;
     658        disp->dirty_rect.p1.y = 0;
     659
     660        return EOK;
    544661}
    545662
     
    590707        }
    591708
    592         return EOK;
     709        return ds_display_update(disp);
     710}
     711
     712/** Display update callback.
     713 *
     714 * Called by backbuffer memory GC when something is rendered into it.
     715 * Updates the display's dirty rectangle.
     716 *
     717 * @param arg Argument (display cast as void *)
     718 * @param rect Rectangle to update
     719 */
     720static void ds_display_update_cb(void *arg, gfx_rect_t *rect)
     721{
     722        ds_display_t *disp = (ds_display_t *) arg;
     723        gfx_rect_t env;
     724
     725        gfx_rect_envelope(&disp->dirty_rect, rect, &env);
     726        disp->dirty_rect = env;
    593727}
    594728
Note: See TracChangeset for help on using the changeset viewer.