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