Home | History | Annotate | Download | only in drm
      1 /**********************************************************
      2  * Copyright 2009-2015 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  * @file
     28  * This file implements the SVGA interface into this winsys, defined
     29  * in drivers/svga/svga_winsys.h.
     30  *
     31  * @author Keith Whitwell
     32  * @author Jose Fonseca
     33  */
     34 
     35 
     36 #include "svga_cmd.h"
     37 #include "svga3d_caps.h"
     38 
     39 #include "util/u_inlines.h"
     40 #include "util/u_math.h"
     41 #include "util/u_memory.h"
     42 #include "pipebuffer/pb_buffer.h"
     43 #include "pipebuffer/pb_bufmgr.h"
     44 #include "svga_winsys.h"
     45 #include "vmw_context.h"
     46 #include "vmw_screen.h"
     47 #include "vmw_surface.h"
     48 #include "vmw_buffer.h"
     49 #include "vmw_fence.h"
     50 #include "vmw_shader.h"
     51 #include "vmw_query.h"
     52 #include "svga3d_surfacedefs.h"
     53 
     54 /**
     55  * Try to get a surface backing buffer from the cache
     56  * if it's this size or smaller.
     57  */
     58 #define VMW_TRY_CACHED_SIZE (2*1024*1024)
     59 
     60 static struct svga_winsys_buffer *
     61 vmw_svga_winsys_buffer_create(struct svga_winsys_screen *sws,
     62                               unsigned alignment,
     63                               unsigned usage,
     64                               unsigned size)
     65 {
     66    struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
     67    struct vmw_buffer_desc desc;
     68    struct pb_manager *provider;
     69    struct pb_buffer *buffer;
     70 
     71    memset(&desc, 0, sizeof desc);
     72    desc.pb_desc.alignment = alignment;
     73    desc.pb_desc.usage = usage;
     74 
     75    if (usage == SVGA_BUFFER_USAGE_PINNED) {
     76       if (vws->pools.query_fenced == NULL && !vmw_query_pools_init(vws))
     77 	 return NULL;
     78       provider = vws->pools.query_fenced;
     79    } else if (usage == SVGA_BUFFER_USAGE_SHADER) {
     80       provider = vws->pools.mob_shader_slab_fenced;
     81    } else
     82       provider = vws->pools.gmr_fenced;
     83 
     84    assert(provider);
     85    buffer = provider->create_buffer(provider, size, &desc.pb_desc);
     86 
     87    if(!buffer && provider == vws->pools.gmr_fenced) {
     88 
     89       assert(provider);
     90       provider = vws->pools.gmr_slab_fenced;
     91       buffer = provider->create_buffer(provider, size, &desc.pb_desc);
     92    }
     93 
     94    if (!buffer)
     95       return NULL;
     96 
     97    return vmw_svga_winsys_buffer_wrap(buffer);
     98 }
     99 
    100 
    101 static void
    102 vmw_svga_winsys_fence_reference(struct svga_winsys_screen *sws,
    103                                 struct pipe_fence_handle **pdst,
    104                                 struct pipe_fence_handle *src)
    105 {
    106     struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
    107 
    108     vmw_fence_reference(vws, pdst, src);
    109 }
    110 
    111 
    112 static int
    113 vmw_svga_winsys_fence_signalled(struct svga_winsys_screen *sws,
    114                                 struct pipe_fence_handle *fence,
    115                                 unsigned flag)
    116 {
    117    struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
    118 
    119    return vmw_fence_signalled(vws, fence, flag);
    120 }
    121 
    122 
    123 static int
    124 vmw_svga_winsys_fence_finish(struct svga_winsys_screen *sws,
    125                              struct pipe_fence_handle *fence,
    126                              unsigned flag)
    127 {
    128    struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
    129 
    130    return vmw_fence_finish(vws, fence, flag);
    131 }
    132 
    133 
    134 
    135 static struct svga_winsys_surface *
    136 vmw_svga_winsys_surface_create(struct svga_winsys_screen *sws,
    137                                SVGA3dSurfaceFlags flags,
    138                                SVGA3dSurfaceFormat format,
    139                                unsigned usage,
    140                                SVGA3dSize size,
    141                                uint32 numLayers,
    142                                uint32 numMipLevels,
    143                                unsigned sampleCount)
    144 {
    145    struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
    146    struct vmw_svga_winsys_surface *surface;
    147    struct vmw_buffer_desc desc;
    148    struct pb_manager *provider;
    149    uint32_t buffer_size;
    150 
    151    memset(&desc, 0, sizeof(desc));
    152    surface = CALLOC_STRUCT(vmw_svga_winsys_surface);
    153    if(!surface)
    154       goto no_surface;
    155 
    156    pipe_reference_init(&surface->refcnt, 1);
    157    p_atomic_set(&surface->validated, 0);
    158    surface->screen = vws;
    159    pipe_mutex_init(surface->mutex);
    160    surface->shared = !!(usage & SVGA_SURFACE_USAGE_SHARED);
    161    provider = (surface->shared) ? vws->pools.gmr : vws->pools.mob_fenced;
    162 
    163    /*
    164     * Used for the backing buffer GB surfaces, and to approximate
    165     * when to flush on non-GB hosts.
    166     */
    167    buffer_size = svga3dsurface_get_serialized_size(format, size, numMipLevels,
    168                                                    numLayers);
    169    if (flags & SVGA3D_SURFACE_BIND_STREAM_OUTPUT)
    170       buffer_size += sizeof(SVGA3dDXSOState);
    171 
    172    if (buffer_size > vws->ioctl.max_texture_size) {
    173       goto no_sid;
    174    }
    175 
    176    if (sws->have_gb_objects) {
    177       SVGAGuestPtr ptr = {0,0};
    178 
    179       /*
    180        * If the backing buffer size is small enough, try to allocate a
    181        * buffer out of the buffer cache. Otherwise, let the kernel allocate
    182        * a suitable buffer for us.
    183        */
    184       if (buffer_size < VMW_TRY_CACHED_SIZE && !surface->shared) {
    185          struct pb_buffer *pb_buf;
    186 
    187          surface->size = buffer_size;
    188          desc.pb_desc.alignment = 4096;
    189          desc.pb_desc.usage = 0;
    190          pb_buf = provider->create_buffer(provider, buffer_size, &desc.pb_desc);
    191          surface->buf = vmw_svga_winsys_buffer_wrap(pb_buf);
    192          if (surface->buf && !vmw_gmr_bufmgr_region_ptr(pb_buf, &ptr))
    193             assert(0);
    194       }
    195 
    196       surface->sid = vmw_ioctl_gb_surface_create(vws, flags, format, usage,
    197                                                  size, numLayers,
    198                                                  numMipLevels, sampleCount,
    199                                                  ptr.gmrId,
    200                                                  surface->buf ? NULL :
    201 						 &desc.region);
    202 
    203       if (surface->sid == SVGA3D_INVALID_ID && surface->buf) {
    204 
    205          /*
    206           * Kernel refused to allocate a surface for us.
    207           * Perhaps something was wrong with our buffer?
    208           * This is really a guard against future new size requirements
    209           * on the backing buffers.
    210           */
    211          vmw_svga_winsys_buffer_destroy(sws, surface->buf);
    212          surface->buf = NULL;
    213          surface->sid = vmw_ioctl_gb_surface_create(vws, flags, format, usage,
    214                                                     size, numLayers,
    215                                                     numMipLevels, sampleCount,
    216                                                     0, &desc.region);
    217          if (surface->sid == SVGA3D_INVALID_ID)
    218             goto no_sid;
    219       }
    220 
    221       /*
    222        * If the kernel created the buffer for us, wrap it into a
    223        * vmw_svga_winsys_buffer.
    224        */
    225       if (surface->buf == NULL) {
    226          struct pb_buffer *pb_buf;
    227 
    228          surface->size = vmw_region_size(desc.region);
    229          desc.pb_desc.alignment = 4096;
    230          desc.pb_desc.usage = VMW_BUFFER_USAGE_SHARED;
    231          pb_buf = provider->create_buffer(provider, surface->size,
    232                                           &desc.pb_desc);
    233          surface->buf = vmw_svga_winsys_buffer_wrap(pb_buf);
    234          if (surface->buf == NULL) {
    235             vmw_ioctl_region_destroy(desc.region);
    236             vmw_ioctl_surface_destroy(vws, surface->sid);
    237             goto no_sid;
    238          }
    239       }
    240    } else {
    241       surface->sid = vmw_ioctl_surface_create(vws, flags, format, usage,
    242                                               size, numLayers, numMipLevels,
    243                                               sampleCount);
    244       if(surface->sid == SVGA3D_INVALID_ID)
    245          goto no_sid;
    246 
    247       /* Best estimate for surface size, used for early flushing. */
    248       surface->size = buffer_size;
    249       surface->buf = NULL;
    250    }
    251 
    252    return svga_winsys_surface(surface);
    253 
    254 no_sid:
    255    if (surface->buf)
    256       vmw_svga_winsys_buffer_destroy(sws, surface->buf);
    257 
    258    FREE(surface);
    259 no_surface:
    260    return NULL;
    261 }
    262 
    263 static boolean
    264 vmw_svga_winsys_surface_can_create(struct svga_winsys_screen *sws,
    265                                SVGA3dSurfaceFormat format,
    266                                SVGA3dSize size,
    267                                uint32 numLayers,
    268                                uint32 numMipLevels)
    269 {
    270    struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
    271    uint32_t buffer_size;
    272 
    273    buffer_size = svga3dsurface_get_serialized_size(format, size,
    274                                                    numMipLevels,
    275                                                    numLayers);
    276    if (buffer_size > vws->ioctl.max_texture_size) {
    277 	return FALSE;
    278    }
    279    return TRUE;
    280 }
    281 
    282 
    283 static void
    284 vmw_svga_winsys_surface_invalidate(struct svga_winsys_screen *sws,
    285                                    struct svga_winsys_surface *surf)
    286 {
    287    /* this is a noop since surface invalidation is not needed for DMA path.
    288     * DMA is enabled when guest-backed surface is not enabled or
    289     * guest-backed dma is enabled.  Since guest-backed dma is enabled
    290     * when guest-backed surface is enabled, that implies DMA is always enabled;
    291     * hence, surface invalidation is not needed.
    292     */
    293 }
    294 
    295 static boolean
    296 vmw_svga_winsys_surface_is_flushed(struct svga_winsys_screen *sws,
    297                                    struct svga_winsys_surface *surface)
    298 {
    299    struct vmw_svga_winsys_surface *vsurf = vmw_svga_winsys_surface(surface);
    300    return (p_atomic_read(&vsurf->validated) == 0);
    301 }
    302 
    303 
    304 static void
    305 vmw_svga_winsys_surface_ref(struct svga_winsys_screen *sws,
    306 			    struct svga_winsys_surface **pDst,
    307 			    struct svga_winsys_surface *src)
    308 {
    309    struct vmw_svga_winsys_surface *d_vsurf = vmw_svga_winsys_surface(*pDst);
    310    struct vmw_svga_winsys_surface *s_vsurf = vmw_svga_winsys_surface(src);
    311 
    312    vmw_svga_winsys_surface_reference(&d_vsurf, s_vsurf);
    313    *pDst = svga_winsys_surface(d_vsurf);
    314 }
    315 
    316 
    317 static void
    318 vmw_svga_winsys_destroy(struct svga_winsys_screen *sws)
    319 {
    320    struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
    321 
    322    vmw_winsys_destroy(vws);
    323 }
    324 
    325 
    326 static SVGA3dHardwareVersion
    327 vmw_svga_winsys_get_hw_version(struct svga_winsys_screen *sws)
    328 {
    329    struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
    330 
    331    if (sws->have_gb_objects)
    332       return SVGA3D_HWVERSION_WS8_B1;
    333 
    334    return (SVGA3dHardwareVersion) vws->ioctl.hwversion;
    335 }
    336 
    337 
    338 static boolean
    339 vmw_svga_winsys_get_cap(struct svga_winsys_screen *sws,
    340                         SVGA3dDevCapIndex index,
    341                         SVGA3dDevCapResult *result)
    342 {
    343    struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
    344 
    345    if (index > vws->ioctl.num_cap_3d ||
    346        index >= SVGA3D_DEVCAP_MAX ||
    347        !vws->ioctl.cap_3d[index].has_cap)
    348       return FALSE;
    349 
    350    *result = vws->ioctl.cap_3d[index].result;
    351    return TRUE;
    352 }
    353 
    354 struct svga_winsys_gb_shader *
    355 vmw_svga_winsys_shader_create(struct svga_winsys_screen *sws,
    356 			      SVGA3dShaderType type,
    357 			      const uint32 *bytecode,
    358 			      uint32 bytecodeLen)
    359 {
    360    struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
    361    struct vmw_svga_winsys_shader *shader;
    362    void *code;
    363 
    364    shader = CALLOC_STRUCT(vmw_svga_winsys_shader);
    365    if(!shader)
    366       goto out_no_shader;
    367 
    368    pipe_reference_init(&shader->refcnt, 1);
    369    p_atomic_set(&shader->validated, 0);
    370    shader->screen = vws;
    371    shader->buf = vmw_svga_winsys_buffer_create(sws, 64,
    372 					       SVGA_BUFFER_USAGE_SHADER,
    373 					       bytecodeLen);
    374    if (!shader->buf)
    375       goto out_no_buf;
    376 
    377    code = vmw_svga_winsys_buffer_map(sws, shader->buf, PIPE_TRANSFER_WRITE);
    378    if (!code)
    379       goto out_no_buf;
    380 
    381    memcpy(code, bytecode, bytecodeLen);
    382    vmw_svga_winsys_buffer_unmap(sws, shader->buf);
    383 
    384    if (!sws->have_vgpu10) {
    385       shader->shid = vmw_ioctl_shader_create(vws, type, bytecodeLen);
    386       if (shader->shid == SVGA3D_INVALID_ID)
    387          goto out_no_shid;
    388    }
    389 
    390    return svga_winsys_shader(shader);
    391 
    392 out_no_shid:
    393    vmw_svga_winsys_buffer_destroy(sws, shader->buf);
    394 out_no_buf:
    395    FREE(shader);
    396 out_no_shader:
    397    return NULL;
    398 }
    399 
    400 void
    401 vmw_svga_winsys_shader_destroy(struct svga_winsys_screen *sws,
    402 			       struct svga_winsys_gb_shader *shader)
    403 {
    404    struct vmw_svga_winsys_shader *d_shader =
    405       vmw_svga_winsys_shader(shader);
    406 
    407    vmw_svga_winsys_shader_reference(&d_shader, NULL);
    408 }
    409 
    410 static void
    411 vmw_svga_winsys_stats_inc(enum svga_stats_count index)
    412 {
    413 }
    414 
    415 static void
    416 vmw_svga_winsys_stats_time_push(enum svga_stats_time index,
    417                                 struct svga_winsys_stats_timeframe *tf)
    418 {
    419 }
    420 
    421 static void
    422 vmw_svga_winsys_stats_time_pop()
    423 {
    424 }
    425 
    426 boolean
    427 vmw_winsys_screen_init_svga(struct vmw_winsys_screen *vws)
    428 {
    429    vws->base.destroy = vmw_svga_winsys_destroy;
    430    vws->base.get_hw_version = vmw_svga_winsys_get_hw_version;
    431    vws->base.get_cap = vmw_svga_winsys_get_cap;
    432    vws->base.context_create = vmw_svga_winsys_context_create;
    433    vws->base.surface_create = vmw_svga_winsys_surface_create;
    434    vws->base.surface_is_flushed = vmw_svga_winsys_surface_is_flushed;
    435    vws->base.surface_reference = vmw_svga_winsys_surface_ref;
    436    vws->base.surface_can_create = vmw_svga_winsys_surface_can_create;
    437    vws->base.surface_invalidate = vmw_svga_winsys_surface_invalidate;
    438    vws->base.buffer_create = vmw_svga_winsys_buffer_create;
    439    vws->base.buffer_map = vmw_svga_winsys_buffer_map;
    440    vws->base.buffer_unmap = vmw_svga_winsys_buffer_unmap;
    441    vws->base.buffer_destroy = vmw_svga_winsys_buffer_destroy;
    442    vws->base.fence_reference = vmw_svga_winsys_fence_reference;
    443    vws->base.fence_signalled = vmw_svga_winsys_fence_signalled;
    444    vws->base.shader_create = vmw_svga_winsys_shader_create;
    445    vws->base.shader_destroy = vmw_svga_winsys_shader_destroy;
    446    vws->base.fence_finish = vmw_svga_winsys_fence_finish;
    447 
    448    vws->base.query_create = vmw_svga_winsys_query_create;
    449    vws->base.query_init = vmw_svga_winsys_query_init;
    450    vws->base.query_destroy = vmw_svga_winsys_query_destroy;
    451    vws->base.query_get_result = vmw_svga_winsys_query_get_result;
    452 
    453    vws->base.stats_inc = vmw_svga_winsys_stats_inc;
    454    vws->base.stats_time_push = vmw_svga_winsys_stats_time_push;
    455    vws->base.stats_time_pop = vmw_svga_winsys_stats_time_pop;
    456 
    457    return TRUE;
    458 }
    459 
    460 
    461