Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /**********************************************************
  2.  * Copyright 2009 VMware, Inc.  All rights reserved.
  3.  *
  4.  * Permission is hereby granted, free of charge, to any person
  5.  * obtaining a copy of this software and associated documentation
  6.  * files (the "Software"), to deal in the Software without
  7.  * restriction, including without limitation the rights to use, copy,
  8.  * modify, merge, publish, distribute, sublicense, and/or sell copies
  9.  * of the Software, and to permit persons to whom the Software is
  10.  * furnished to do so, subject to the following conditions:
  11.  *
  12.  * The above copyright notice and this permission notice shall be
  13.  * included in all copies or substantial portions of the Software.
  14.  *
  15.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16.  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  17.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  18.  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  19.  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  20.  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  21.  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  22.  * SOFTWARE.
  23.  *
  24.  **********************************************************/
  25.  
  26.  
  27. #include "svga_cmd.h"
  28.  
  29. #include "util/u_debug.h"
  30. #include "util/u_memory.h"
  31. #include "util/u_debug_stack.h"
  32. #include "pipebuffer/pb_buffer.h"
  33. #include "pipebuffer/pb_validate.h"
  34.  
  35. #include "svga_winsys.h"
  36. #include "vmw_context.h"
  37. #include "vmw_screen.h"
  38. #include "vmw_buffer.h"
  39. #include "vmw_surface.h"
  40. #include "vmw_fence.h"
  41.  
  42. #define VMW_COMMAND_SIZE (64*1024)
  43. #define VMW_SURFACE_RELOCS (1024)
  44. #define VMW_REGION_RELOCS (512)
  45.  
  46. #define VMW_MUST_FLUSH_STACK 8
  47.  
  48. struct vmw_region_relocation
  49. {
  50.    struct SVGAGuestPtr *where;
  51.    struct pb_buffer *buffer;
  52.    /* TODO: put offset info inside where */
  53.    uint32 offset;
  54. };
  55.  
  56. struct vmw_svga_winsys_context
  57. {
  58.    struct svga_winsys_context base;
  59.  
  60.    struct vmw_winsys_screen *vws;
  61.  
  62. #ifdef DEBUG
  63.    boolean must_flush;
  64.    struct debug_stack_frame must_flush_stack[VMW_MUST_FLUSH_STACK];
  65. #endif
  66.  
  67.    struct {
  68.       uint8_t buffer[VMW_COMMAND_SIZE];
  69.       uint32_t size;
  70.       uint32_t used;
  71.       uint32_t reserved;
  72.    } command;
  73.  
  74.    struct {
  75.       struct vmw_svga_winsys_surface *handles[VMW_SURFACE_RELOCS];
  76.       uint32_t size;
  77.       uint32_t used;
  78.       uint32_t staged;
  79.       uint32_t reserved;
  80.    } surface;
  81.    
  82.    struct {
  83.       struct vmw_region_relocation relocs[VMW_REGION_RELOCS];
  84.       uint32_t size;
  85.       uint32_t used;
  86.       uint32_t staged;
  87.       uint32_t reserved;
  88.    } region;
  89.  
  90.    struct pb_validate *validate;
  91.  
  92.    /**
  93.     * The amount of GMR that is referred by the commands currently batched
  94.     * in the context.
  95.     */
  96.    uint32_t seen_regions;
  97.  
  98.    /**
  99.     * Whether this context should fail to reserve more commands, not because it
  100.     * ran out of command space, but because a substantial ammount of GMR was
  101.     * referred.
  102.     */
  103.    boolean preemptive_flush;
  104. };
  105.  
  106.  
  107. static INLINE struct vmw_svga_winsys_context *
  108. vmw_svga_winsys_context(struct svga_winsys_context *swc)
  109. {
  110.    assert(swc);
  111.    return (struct vmw_svga_winsys_context *)swc;
  112. }
  113.  
  114.  
  115. static INLINE unsigned
  116. vmw_translate_to_pb_flags(unsigned flags)
  117. {
  118.    unsigned f = 0;
  119.    if (flags & SVGA_RELOC_READ)
  120.       f |= PB_USAGE_GPU_READ;
  121.  
  122.    if (flags & SVGA_RELOC_WRITE)
  123.       f |= PB_USAGE_GPU_WRITE;
  124.  
  125.    return f;
  126. }
  127.  
  128. static enum pipe_error
  129. vmw_swc_flush(struct svga_winsys_context *swc,
  130.               struct pipe_fence_handle **pfence)
  131. {
  132.    struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
  133.    struct pipe_fence_handle *fence = NULL;
  134.    unsigned i;
  135.    enum pipe_error ret;
  136.  
  137.    ret = pb_validate_validate(vswc->validate);
  138.    assert(ret == PIPE_OK);
  139.    if(ret == PIPE_OK) {
  140.    
  141.       /* Apply relocations */
  142.       for(i = 0; i < vswc->region.used; ++i) {
  143.          struct vmw_region_relocation *reloc = &vswc->region.relocs[i];
  144.          struct SVGAGuestPtr ptr;
  145.  
  146.          if(!vmw_gmr_bufmgr_region_ptr(reloc->buffer, &ptr))
  147.             assert(0);
  148.  
  149.          ptr.offset += reloc->offset;
  150.  
  151.          *reloc->where = ptr;
  152.       }
  153.  
  154.       if (vswc->command.used || pfence != NULL)
  155.          vmw_ioctl_command(vswc->vws,
  156.                            vswc->base.cid,
  157.                            0,
  158.                            vswc->command.buffer,
  159.                            vswc->command.used,
  160.                            &fence);
  161.  
  162.       pb_validate_fence(vswc->validate, fence);
  163.    }
  164.  
  165.    vswc->command.used = 0;
  166.    vswc->command.reserved = 0;
  167.  
  168.    for(i = 0; i < vswc->surface.used + vswc->surface.staged; ++i) {
  169.       struct vmw_svga_winsys_surface *vsurf =
  170.          vswc->surface.handles[i];
  171.       p_atomic_dec(&vsurf->validated);
  172.       vmw_svga_winsys_surface_reference(&vswc->surface.handles[i], NULL);
  173.    }
  174.  
  175.    vswc->surface.used = 0;
  176.    vswc->surface.reserved = 0;
  177.  
  178.    for(i = 0; i < vswc->region.used + vswc->region.staged; ++i) {
  179.       pb_reference(&vswc->region.relocs[i].buffer, NULL);
  180.    }
  181.  
  182.    vswc->region.used = 0;
  183.    vswc->region.reserved = 0;
  184.  
  185. #ifdef DEBUG
  186.    vswc->must_flush = FALSE;
  187. #endif
  188.    vswc->preemptive_flush = FALSE;
  189.    vswc->seen_regions = 0;
  190.  
  191.    if(pfence)
  192.       vmw_fence_reference(vswc->vws, pfence, fence);
  193.  
  194.    vmw_fence_reference(vswc->vws, &fence, NULL);
  195.  
  196.    return ret;
  197. }
  198.  
  199.  
  200. static void *
  201. vmw_swc_reserve(struct svga_winsys_context *swc,
  202.                 uint32_t nr_bytes, uint32_t nr_relocs )
  203. {
  204.    struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
  205.  
  206. #ifdef DEBUG
  207.    /* Check if somebody forgot to check the previous failure */
  208.    if(vswc->must_flush) {
  209.       debug_printf("Forgot to flush:\n");
  210.       debug_backtrace_dump(vswc->must_flush_stack, VMW_MUST_FLUSH_STACK);
  211.       assert(!vswc->must_flush);
  212.    }
  213. #endif
  214.  
  215.    assert(nr_bytes <= vswc->command.size);
  216.    if(nr_bytes > vswc->command.size)
  217.       return NULL;
  218.  
  219.    if(vswc->preemptive_flush ||
  220.       vswc->command.used + nr_bytes > vswc->command.size ||
  221.       vswc->surface.used + nr_relocs > vswc->surface.size ||
  222.       vswc->region.used + nr_relocs > vswc->region.size) {
  223. #ifdef DEBUG
  224.       vswc->must_flush = TRUE;
  225.       debug_backtrace_capture(vswc->must_flush_stack, 1,
  226.                               VMW_MUST_FLUSH_STACK);
  227. #endif
  228.       return NULL;
  229.    }
  230.  
  231.    assert(vswc->command.used + nr_bytes <= vswc->command.size);
  232.    assert(vswc->surface.used + nr_relocs <= vswc->surface.size);
  233.    assert(vswc->region.used + nr_relocs <= vswc->region.size);
  234.    
  235.    vswc->command.reserved = nr_bytes;
  236.    vswc->surface.reserved = nr_relocs;
  237.    vswc->surface.staged = 0;
  238.    vswc->region.reserved = nr_relocs;
  239.    vswc->region.staged = 0;
  240.    
  241.    return vswc->command.buffer + vswc->command.used;
  242. }
  243.  
  244.  
  245. static void
  246. vmw_swc_surface_relocation(struct svga_winsys_context *swc,
  247.                            uint32 *where,
  248.                            struct svga_winsys_surface *surface,
  249.                            unsigned flags)
  250. {
  251.    struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
  252.    struct vmw_svga_winsys_surface *vsurf;
  253.  
  254.    if(!surface) {
  255.       *where = SVGA3D_INVALID_ID;
  256.       return;
  257.    }
  258.  
  259.    assert(vswc->surface.staged < vswc->surface.reserved);
  260.  
  261.    vsurf = vmw_svga_winsys_surface(surface);
  262.  
  263.    *where = vsurf->sid;
  264.  
  265.    vmw_svga_winsys_surface_reference(&vswc->surface.handles[vswc->surface.used + vswc->surface.staged], vsurf);
  266.    p_atomic_inc(&vsurf->validated);
  267.    ++vswc->surface.staged;
  268. }
  269.  
  270.  
  271. static void
  272. vmw_swc_region_relocation(struct svga_winsys_context *swc,
  273.                           struct SVGAGuestPtr *where,
  274.                           struct svga_winsys_buffer *buffer,
  275.                           uint32 offset,
  276.                           unsigned flags)
  277. {
  278.    struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
  279.    struct vmw_region_relocation *reloc;
  280.    unsigned translated_flags;
  281.    enum pipe_error ret;
  282.    
  283.    assert(vswc->region.staged < vswc->region.reserved);
  284.  
  285.    reloc = &vswc->region.relocs[vswc->region.used + vswc->region.staged];
  286.    reloc->where = where;
  287.    pb_reference(&reloc->buffer, vmw_pb_buffer(buffer));
  288.    reloc->offset = offset;
  289.  
  290.    ++vswc->region.staged;
  291.  
  292.    translated_flags = vmw_translate_to_pb_flags(flags);
  293.    ret = pb_validate_add_buffer(vswc->validate, reloc->buffer, translated_flags);
  294.    /* TODO: Update pipebuffer to reserve buffers and not fail here */
  295.    assert(ret == PIPE_OK);
  296.    (void)ret;
  297.  
  298.    /*
  299.     * Flush preemptively the FIFO commands to keep the GMR working set within
  300.     * the GMR pool size.
  301.     *
  302.     * This is necessary for applications like SPECviewperf that generate huge
  303.     * amounts of immediate vertex data, so that we don't pile up too much of
  304.     * that vertex data neither in the guest nor in the host.
  305.     *
  306.     * Note that in the current implementation if a region is referred twice in
  307.     * a command stream, it will be accounted twice. We could detect repeated
  308.     * regions and count only once, but there is no incentive to do that, since
  309.     * regions are typically short-lived; always referred in a single command;
  310.     * and at the worst we just flush the commands a bit sooner, which for the
  311.     * SVGA virtual device it's not a performance issue since flushing commands
  312.     * to the FIFO won't cause flushing in the host.
  313.     */
  314.    vswc->seen_regions += reloc->buffer->size;
  315.    if(vswc->seen_regions >= VMW_GMR_POOL_SIZE/3)
  316.       vswc->preemptive_flush = TRUE;
  317. }
  318.  
  319.  
  320. static void
  321. vmw_swc_commit(struct svga_winsys_context *swc)
  322. {
  323.    struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
  324.  
  325.    assert(vswc->command.reserved);
  326.    assert(vswc->command.used + vswc->command.reserved <= vswc->command.size);
  327.    vswc->command.used += vswc->command.reserved;
  328.    vswc->command.reserved = 0;
  329.  
  330.    assert(vswc->surface.staged <= vswc->surface.reserved);
  331.    assert(vswc->surface.used + vswc->surface.staged <= vswc->surface.size);
  332.    vswc->surface.used += vswc->surface.staged;
  333.    vswc->surface.staged = 0;
  334.    vswc->surface.reserved = 0;
  335.  
  336.    assert(vswc->region.staged <= vswc->region.reserved);
  337.    assert(vswc->region.used + vswc->region.staged <= vswc->region.size);
  338.    vswc->region.used += vswc->region.staged;
  339.    vswc->region.staged = 0;
  340.    vswc->region.reserved = 0;
  341. }
  342.  
  343.  
  344. static void
  345. vmw_swc_destroy(struct svga_winsys_context *swc)
  346. {
  347.    struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
  348.    unsigned i;
  349.  
  350.    for(i = 0; i < vswc->region.used; ++i) {
  351.       pb_reference(&vswc->region.relocs[i].buffer, NULL);
  352.    }
  353.  
  354.    for(i = 0; i < vswc->surface.used; ++i) {
  355.       p_atomic_dec(&vswc->surface.handles[i]->validated);
  356.       vmw_svga_winsys_surface_reference(&vswc->surface.handles[i], NULL);
  357.    }
  358.    pb_validate_destroy(vswc->validate);
  359.    vmw_ioctl_context_destroy(vswc->vws, swc->cid);
  360.    FREE(vswc);
  361. }
  362.  
  363.  
  364. struct svga_winsys_context *
  365. vmw_svga_winsys_context_create(struct svga_winsys_screen *sws)
  366. {
  367.    struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
  368.    struct vmw_svga_winsys_context *vswc;
  369.  
  370.    vswc = CALLOC_STRUCT(vmw_svga_winsys_context);
  371.    if(!vswc)
  372.       return NULL;
  373.  
  374.    vswc->base.destroy = vmw_swc_destroy;
  375.    vswc->base.reserve = vmw_swc_reserve;
  376.    vswc->base.surface_relocation = vmw_swc_surface_relocation;
  377.    vswc->base.region_relocation = vmw_swc_region_relocation;
  378.    vswc->base.commit = vmw_swc_commit;
  379.    vswc->base.flush = vmw_swc_flush;
  380.  
  381.    vswc->base.cid = vmw_ioctl_context_create(vws);
  382.  
  383.    vswc->vws = vws;
  384.  
  385.    vswc->command.size = VMW_COMMAND_SIZE;
  386.    vswc->surface.size = VMW_SURFACE_RELOCS;
  387.    vswc->region.size = VMW_REGION_RELOCS;
  388.  
  389.    vswc->validate = pb_validate_create();
  390.    if(!vswc->validate) {
  391.       FREE(vswc);
  392.       return NULL;
  393.    }
  394.  
  395.    return &vswc->base;
  396. }
  397.