Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /**************************************************************************
  2.  *
  3.  * Copyright 2009 Younes Manton.
  4.  * All Rights Reserved.
  5.  *
  6.  * Permission is hereby granted, free of charge, to any person obtaining a
  7.  * copy of this software and associated documentation files (the
  8.  * "Software"), to deal in the Software without restriction, including
  9.  * without limitation the rights to use, copy, modify, merge, publish,
  10.  * distribute, sub license, and/or sell copies of the Software, and to
  11.  * permit persons to whom the Software is furnished to do so, subject to
  12.  * the following conditions:
  13.  *
  14.  * The above copyright notice and this permission notice (including the
  15.  * next paragraph) shall be included in all copies or substantial portions
  16.  * of the Software.
  17.  *
  18.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  19.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  20.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
  21.  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
  22.  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  23.  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  24.  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  25.  *
  26.  **************************************************************************/
  27.  
  28. /* directly referenced from target Makefile, because of X dependencies */
  29.  
  30. #include <sys/types.h>
  31. #include <sys/stat.h>
  32. #include <fcntl.h>
  33.  
  34. #include <X11/Xlib-xcb.h>
  35. #include <xcb/dri2.h>
  36. #include <xf86drm.h>
  37.  
  38. #include "pipe/p_screen.h"
  39. #include "pipe/p_context.h"
  40. #include "pipe/p_state.h"
  41. #include "state_tracker/drm_driver.h"
  42.  
  43. #include "util/u_memory.h"
  44. #include "util/u_hash.h"
  45. #include "util/u_hash_table.h"
  46. #include "util/u_inlines.h"
  47.  
  48. #include "vl/vl_compositor.h"
  49. #include "vl/vl_winsys.h"
  50.  
  51. struct vl_dri_screen
  52. {
  53.    struct vl_screen base;
  54.    xcb_connection_t *conn;
  55.    xcb_drawable_t drawable;
  56.  
  57.    unsigned width, height;
  58.  
  59.    bool current_buffer;
  60.    uint32_t buffer_names[2];
  61.    struct u_rect dirty_areas[2];
  62.  
  63.    bool flushed;
  64.    xcb_dri2_swap_buffers_cookie_t swap_cookie;
  65.    xcb_dri2_wait_sbc_cookie_t wait_cookie;
  66.    xcb_dri2_get_buffers_cookie_t buffers_cookie;
  67.  
  68.    int64_t last_ust, ns_frame, last_msc, next_msc;
  69. };
  70.  
  71. static const unsigned int attachments[1] = { XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT };
  72.  
  73. static void
  74. vl_dri2_handle_stamps(struct vl_dri_screen* scrn,
  75.                       uint32_t ust_hi, uint32_t ust_lo,
  76.                       uint32_t msc_hi, uint32_t msc_lo)
  77. {
  78.    int64_t ust = ((((uint64_t)ust_hi) << 32) | ust_lo) * 1000;
  79.    int64_t msc = (((uint64_t)msc_hi) << 32) | msc_lo;
  80.  
  81.    if (scrn->last_ust && scrn->last_msc && (ust > scrn->last_ust) && (msc > scrn->last_msc))
  82.       scrn->ns_frame = (ust - scrn->last_ust) / (msc - scrn->last_msc);
  83.  
  84.    scrn->last_ust = ust;
  85.    scrn->last_msc = msc;
  86. }
  87.  
  88. static xcb_dri2_get_buffers_reply_t*
  89. vl_dri2_get_flush_reply(struct vl_dri_screen *scrn)
  90. {
  91.    xcb_dri2_wait_sbc_reply_t *wait_sbc_reply;
  92.  
  93.    assert(scrn);
  94.  
  95.    if (!scrn->flushed)
  96.       return NULL;
  97.  
  98.    scrn->flushed = false;
  99.  
  100.    free(xcb_dri2_swap_buffers_reply(scrn->conn, scrn->swap_cookie, NULL));
  101.  
  102.    wait_sbc_reply = xcb_dri2_wait_sbc_reply(scrn->conn, scrn->wait_cookie, NULL);
  103.    if (!wait_sbc_reply)
  104.       return NULL;
  105.    vl_dri2_handle_stamps(scrn, wait_sbc_reply->ust_hi, wait_sbc_reply->ust_lo,
  106.                          wait_sbc_reply->msc_hi, wait_sbc_reply->msc_lo);
  107.    free(wait_sbc_reply);
  108.  
  109.    return xcb_dri2_get_buffers_reply(scrn->conn, scrn->buffers_cookie, NULL);
  110. }
  111.  
  112. static void
  113. vl_dri2_flush_frontbuffer(struct pipe_screen *screen,
  114.                           struct pipe_resource *resource,
  115.                           unsigned level, unsigned layer,
  116.                           void *context_private)
  117. {
  118.    struct vl_dri_screen *scrn = (struct vl_dri_screen*)context_private;
  119.    uint32_t msc_hi, msc_lo;
  120.  
  121.    assert(screen);
  122.    assert(resource);
  123.    assert(context_private);
  124.  
  125.    free(vl_dri2_get_flush_reply(scrn));
  126.  
  127.    msc_hi = scrn->next_msc >> 32;
  128.    msc_lo = scrn->next_msc & 0xFFFFFFFF;
  129.  
  130.    scrn->swap_cookie = xcb_dri2_swap_buffers_unchecked(scrn->conn, scrn->drawable, msc_hi, msc_lo, 0, 0, 0, 0);
  131.    scrn->wait_cookie = xcb_dri2_wait_sbc_unchecked(scrn->conn, scrn->drawable, 0, 0);
  132.    scrn->buffers_cookie = xcb_dri2_get_buffers_unchecked(scrn->conn, scrn->drawable, 1, 1, attachments);
  133.  
  134.    scrn->flushed = true;
  135.    scrn->current_buffer = !scrn->current_buffer;
  136. }
  137.  
  138. static void
  139. vl_dri2_destroy_drawable(struct vl_dri_screen *scrn)
  140. {
  141.    xcb_void_cookie_t destroy_cookie;
  142.    if (scrn->drawable) {
  143.       free(vl_dri2_get_flush_reply(scrn));
  144.       destroy_cookie = xcb_dri2_destroy_drawable_checked(scrn->conn, scrn->drawable);
  145.       /* ignore any error here, since the drawable can be destroyed long ago */
  146.       free(xcb_request_check(scrn->conn, destroy_cookie));
  147.    }
  148. }
  149.  
  150. static void
  151. vl_dri2_set_drawable(struct vl_dri_screen *scrn, Drawable drawable)
  152. {
  153.    assert(scrn);
  154.    assert(drawable);
  155.  
  156.    if (scrn->drawable == drawable)
  157.       return;
  158.  
  159.    vl_dri2_destroy_drawable(scrn);
  160.  
  161.    xcb_dri2_create_drawable(scrn->conn, drawable);
  162.    scrn->current_buffer = false;
  163.    vl_compositor_reset_dirty_area(&scrn->dirty_areas[0]);
  164.    vl_compositor_reset_dirty_area(&scrn->dirty_areas[1]);
  165.    scrn->drawable = drawable;
  166. }
  167.  
  168. struct pipe_resource*
  169. vl_screen_texture_from_drawable(struct vl_screen *vscreen, Drawable drawable)
  170. {
  171.    struct vl_dri_screen *scrn = (struct vl_dri_screen*)vscreen;
  172.  
  173.    struct winsys_handle dri2_handle;
  174.    struct pipe_resource template, *tex;
  175.  
  176.    xcb_dri2_get_buffers_reply_t *reply;
  177.    xcb_dri2_dri2_buffer_t *buffers, *back_left;
  178.  
  179.    unsigned i;
  180.  
  181.    assert(scrn);
  182.  
  183.    vl_dri2_set_drawable(scrn, drawable);
  184.    reply = vl_dri2_get_flush_reply(scrn);
  185.    if (!reply) {
  186.       xcb_dri2_get_buffers_cookie_t cookie;
  187.       cookie = xcb_dri2_get_buffers_unchecked(scrn->conn, drawable, 1, 1, attachments);
  188.       reply = xcb_dri2_get_buffers_reply(scrn->conn, cookie, NULL);
  189.    }
  190.    if (!reply)
  191.       return NULL;
  192.  
  193.    buffers = xcb_dri2_get_buffers_buffers(reply);
  194.    if (!buffers)  {
  195.       free(reply);
  196.       return NULL;
  197.    }
  198.  
  199.    for (i = 0; i < reply->count; ++i) {
  200.       if (buffers[i].attachment == XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT) {
  201.          back_left = &buffers[i];
  202.          break;
  203.       }
  204.    }
  205.  
  206.    if (i == reply->count) {
  207.       free(reply);
  208.       return NULL;
  209.    }
  210.  
  211.    if (reply->width != scrn->width || reply->height != scrn->height) {
  212.       vl_compositor_reset_dirty_area(&scrn->dirty_areas[0]);
  213.       vl_compositor_reset_dirty_area(&scrn->dirty_areas[1]);
  214.       scrn->width = reply->width;
  215.       scrn->height = reply->height;
  216.  
  217.    } else if (back_left->name != scrn->buffer_names[scrn->current_buffer]) {
  218.       vl_compositor_reset_dirty_area(&scrn->dirty_areas[scrn->current_buffer]);
  219.       scrn->buffer_names[scrn->current_buffer] = back_left->name;
  220.    }
  221.  
  222.    memset(&dri2_handle, 0, sizeof(dri2_handle));
  223.    dri2_handle.type = DRM_API_HANDLE_TYPE_SHARED;
  224.    dri2_handle.handle = back_left->name;
  225.    dri2_handle.stride = back_left->pitch;
  226.  
  227.    memset(&template, 0, sizeof(template));
  228.    template.target = PIPE_TEXTURE_2D;
  229.    template.format = PIPE_FORMAT_B8G8R8X8_UNORM;
  230.    template.last_level = 0;
  231.    template.width0 = reply->width;
  232.    template.height0 = reply->height;
  233.    template.depth0 = 1;
  234.    template.array_size = 1;
  235.    template.usage = PIPE_USAGE_STATIC;
  236.    template.bind = PIPE_BIND_RENDER_TARGET;
  237.    template.flags = 0;
  238.  
  239.    tex = scrn->base.pscreen->resource_from_handle(scrn->base.pscreen, &template, &dri2_handle);
  240.    free(reply);
  241.  
  242.    return tex;
  243. }
  244.  
  245. struct u_rect *
  246. vl_screen_get_dirty_area(struct vl_screen *vscreen)
  247. {
  248.    struct vl_dri_screen *scrn = (struct vl_dri_screen*)vscreen;
  249.    assert(scrn);
  250.    return &scrn->dirty_areas[scrn->current_buffer];
  251. }
  252.  
  253. uint64_t
  254. vl_screen_get_timestamp(struct vl_screen *vscreen, Drawable drawable)
  255. {
  256.    struct vl_dri_screen *scrn = (struct vl_dri_screen*)vscreen;
  257.    xcb_dri2_get_msc_cookie_t cookie;
  258.    xcb_dri2_get_msc_reply_t *reply;
  259.  
  260.    assert(scrn);
  261.  
  262.    vl_dri2_set_drawable(scrn, drawable);
  263.    if (!scrn->last_ust) {
  264.       cookie = xcb_dri2_get_msc_unchecked(scrn->conn, drawable);
  265.       reply = xcb_dri2_get_msc_reply(scrn->conn, cookie, NULL);
  266.  
  267.       if (reply) {
  268.          vl_dri2_handle_stamps(scrn, reply->ust_hi, reply->ust_lo,
  269.                                reply->msc_hi, reply->msc_lo);
  270.          free(reply);
  271.       }
  272.    }
  273.    return scrn->last_ust;
  274. }
  275.  
  276. void
  277. vl_screen_set_next_timestamp(struct vl_screen *vscreen, uint64_t stamp)
  278. {
  279.    struct vl_dri_screen *scrn = (struct vl_dri_screen*)vscreen;
  280.    assert(scrn);
  281.    if (stamp && scrn->last_ust && scrn->ns_frame && scrn->last_msc)
  282.       scrn->next_msc = ((int64_t)stamp - scrn->last_ust + scrn->ns_frame/2) / scrn->ns_frame + scrn->last_msc;
  283.    else
  284.       scrn->next_msc = 0;
  285. }
  286.  
  287. void*
  288. vl_screen_get_private(struct vl_screen *vscreen)
  289. {
  290.    return vscreen;
  291. }
  292.  
  293. struct vl_screen*
  294. vl_screen_create(Display *display, int screen)
  295. {
  296.    struct vl_dri_screen *scrn;
  297.    const xcb_query_extension_reply_t *extension;
  298.    xcb_dri2_query_version_cookie_t dri2_query_cookie;
  299.    xcb_dri2_query_version_reply_t *dri2_query = NULL;
  300.    xcb_dri2_connect_cookie_t connect_cookie;
  301.    xcb_dri2_connect_reply_t *connect = NULL;
  302.    xcb_dri2_authenticate_cookie_t authenticate_cookie;
  303.    xcb_dri2_authenticate_reply_t *authenticate = NULL;
  304.    xcb_screen_iterator_t s;
  305.    xcb_generic_error_t *error = NULL;
  306.    char *device_name;
  307.    int fd, device_name_length;
  308.  
  309.    drm_magic_t magic;
  310.  
  311.    assert(display);
  312.  
  313.    scrn = CALLOC_STRUCT(vl_dri_screen);
  314.    if (!scrn)
  315.       return NULL;
  316.  
  317.    scrn->conn = XGetXCBConnection(display);
  318.    if (!scrn->conn)
  319.       goto free_screen;
  320.  
  321.    xcb_prefetch_extension_data(scrn->conn, &xcb_dri2_id);
  322.  
  323.    extension = xcb_get_extension_data(scrn->conn, &xcb_dri2_id);
  324.    if (!(extension && extension->present))
  325.       goto free_screen;
  326.  
  327.    dri2_query_cookie = xcb_dri2_query_version (scrn->conn, XCB_DRI2_MAJOR_VERSION, XCB_DRI2_MINOR_VERSION);
  328.    dri2_query = xcb_dri2_query_version_reply (scrn->conn, dri2_query_cookie, &error);
  329.    if (dri2_query == NULL || error != NULL || dri2_query->minor_version < 2)
  330.       goto free_screen;
  331.  
  332.    s = xcb_setup_roots_iterator(xcb_get_setup(scrn->conn));
  333.    while (screen--)
  334.         xcb_screen_next(&s);
  335.    connect_cookie = xcb_dri2_connect_unchecked(scrn->conn, s.data->root, XCB_DRI2_DRIVER_TYPE_DRI);
  336.    connect = xcb_dri2_connect_reply(scrn->conn, connect_cookie, NULL);
  337.    if (connect == NULL || connect->driver_name_length + connect->device_name_length == 0)
  338.       goto free_screen;
  339.  
  340.    device_name_length = xcb_dri2_connect_device_name_length(connect);
  341.    device_name = CALLOC(1, device_name_length + 1);
  342.    memcpy(device_name, xcb_dri2_connect_device_name(connect), device_name_length);
  343.    fd = open(device_name, O_RDWR);
  344.    free(device_name);
  345.  
  346.    if (fd < 0)
  347.       goto free_screen;
  348.  
  349.    if (drmGetMagic(fd, &magic))
  350.       goto free_screen;
  351.  
  352.    authenticate_cookie = xcb_dri2_authenticate_unchecked(scrn->conn, s.data->root, magic);
  353.    authenticate = xcb_dri2_authenticate_reply(scrn->conn, authenticate_cookie, NULL);
  354.  
  355.    if (authenticate == NULL || !authenticate->authenticated)
  356.       goto free_screen;
  357.  
  358.    scrn->base.pscreen = driver_descriptor.create_screen(fd);
  359.    if (!scrn->base.pscreen)
  360.       goto free_screen;
  361.  
  362.    scrn->base.pscreen->flush_frontbuffer = vl_dri2_flush_frontbuffer;
  363.    vl_compositor_reset_dirty_area(&scrn->dirty_areas[0]);
  364.    vl_compositor_reset_dirty_area(&scrn->dirty_areas[1]);
  365.  
  366.    free(dri2_query);
  367.    free(connect);
  368.    free(authenticate);
  369.  
  370.    return &scrn->base;
  371.  
  372. free_screen:
  373.    FREE(scrn);
  374.  
  375.    free(dri2_query);
  376.    free(connect);
  377.    free(authenticate);
  378.    free(error);
  379.  
  380.    return NULL;
  381. }
  382.  
  383. void vl_screen_destroy(struct vl_screen *vscreen)
  384. {
  385.    struct vl_dri_screen *scrn = (struct vl_dri_screen*)vscreen;
  386.  
  387.    assert(vscreen);
  388.  
  389.    if (scrn->flushed) {
  390.       free(xcb_dri2_swap_buffers_reply(scrn->conn, scrn->swap_cookie, NULL));
  391.       free(xcb_dri2_wait_sbc_reply(scrn->conn, scrn->wait_cookie, NULL));
  392.       free(xcb_dri2_get_buffers_reply(scrn->conn, scrn->buffers_cookie, NULL));
  393.    }
  394.  
  395.    vl_dri2_destroy_drawable(scrn);
  396.    scrn->base.pscreen->destroy(scrn->base.pscreen);
  397.    FREE(scrn);
  398. }
  399.