Path: blob/21.2-virgl/src/gallium/winsys/svga/drm/vmw_screen_svga.c
4573 views
/**********************************************************1* Copyright 2009-2015 VMware, Inc. All rights reserved.2*3* Permission is hereby granted, free of charge, to any person4* obtaining a copy of this software and associated documentation5* files (the "Software"), to deal in the Software without6* restriction, including without limitation the rights to use, copy,7* modify, merge, publish, distribute, sublicense, and/or sell copies8* of the Software, and to permit persons to whom the Software is9* furnished to do so, subject to the following conditions:10*11* The above copyright notice and this permission notice shall be12* included in all copies or substantial portions of the Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,15* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF16* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND17* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS18* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN19* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN20* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE21* SOFTWARE.22*23**********************************************************/2425/**26* @file27* This file implements the SVGA interface into this winsys, defined28* in drivers/svga/svga_winsys.h.29*30* @author Keith Whitwell31* @author Jose Fonseca32*/3334#include <libsync.h>3536#include "svga_cmd.h"37#include "svga3d_caps.h"3839#include "util/os_file.h"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_msg.h"52#include "vmw_shader.h"53#include "vmw_query.h"54#include "svga3d_surfacedefs.h"5556/**57* Try to get a surface backing buffer from the cache58* if it's this size or smaller.59*/60#define VMW_TRY_CACHED_SIZE (2*1024*1024)6162static struct svga_winsys_buffer *63vmw_svga_winsys_buffer_create(struct svga_winsys_screen *sws,64unsigned alignment,65unsigned usage,66unsigned size)67{68struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);69struct vmw_buffer_desc desc;70struct pb_manager *provider;71struct pb_buffer *buffer;7273memset(&desc, 0, sizeof desc);74desc.pb_desc.alignment = alignment;75desc.pb_desc.usage = usage;7677if (usage == SVGA_BUFFER_USAGE_PINNED) {78if (vws->pools.query_fenced == NULL && !vmw_query_pools_init(vws))79return NULL;80provider = vws->pools.query_fenced;81} else if (usage == SVGA_BUFFER_USAGE_SHADER) {82provider = vws->pools.mob_shader_slab_fenced;83} else {84if (size > VMW_GMR_POOL_SIZE)85return NULL;86provider = vws->pools.gmr_fenced;87}8889assert(provider);90buffer = provider->create_buffer(provider, size, &desc.pb_desc);9192if(!buffer && provider == vws->pools.gmr_fenced) {9394assert(provider);95provider = vws->pools.gmr_slab_fenced;96buffer = provider->create_buffer(provider, size, &desc.pb_desc);97}9899if (!buffer)100return NULL;101102return vmw_svga_winsys_buffer_wrap(buffer);103}104105106static void107vmw_svga_winsys_fence_reference(struct svga_winsys_screen *sws,108struct pipe_fence_handle **pdst,109struct pipe_fence_handle *src)110{111struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);112113vmw_fence_reference(vws, pdst, src);114}115116117static int118vmw_svga_winsys_fence_signalled(struct svga_winsys_screen *sws,119struct pipe_fence_handle *fence,120unsigned flag)121{122struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);123124return vmw_fence_signalled(vws, fence, flag);125}126127128static int129vmw_svga_winsys_fence_finish(struct svga_winsys_screen *sws,130struct pipe_fence_handle *fence,131uint64_t timeout,132unsigned flag)133{134struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);135136return vmw_fence_finish(vws, fence, timeout, flag);137}138139140static int141vmw_svga_winsys_fence_get_fd(struct svga_winsys_screen *sws,142struct pipe_fence_handle *fence,143boolean duplicate)144{145if (duplicate)146return os_dupfd_cloexec(vmw_fence_get_fd(fence));147else148return vmw_fence_get_fd(fence);149}150151152static void153vmw_svga_winsys_fence_create_fd(struct svga_winsys_screen *sws,154struct pipe_fence_handle **fence,155int32_t fd)156{157*fence = vmw_fence_create(NULL, 0, 0, 0, os_dupfd_cloexec(fd));158}159160static int161vmw_svga_winsys_fence_server_sync(struct svga_winsys_screen *sws,162int32_t *context_fd,163struct pipe_fence_handle *fence)164{165int32_t fd = sws->fence_get_fd(sws, fence, FALSE);166167/* If we don't have fd, we don't need to merge fd into the context's fd. */168if (fd == -1)169return 0;170171return sync_accumulate("vmwgfx", context_fd, fd);172}173174175static struct svga_winsys_surface *176vmw_svga_winsys_surface_create(struct svga_winsys_screen *sws,177SVGA3dSurfaceAllFlags flags,178SVGA3dSurfaceFormat format,179unsigned usage,180SVGA3dSize size,181uint32 numLayers,182uint32 numMipLevels,183unsigned sampleCount)184{185struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);186struct vmw_svga_winsys_surface *surface;187struct vmw_buffer_desc desc;188struct pb_manager *provider;189uint32_t buffer_size;190uint32_t num_samples = 1;191SVGA3dMSPattern multisample_pattern = SVGA3D_MS_PATTERN_NONE;192SVGA3dMSQualityLevel quality_level = SVGA3D_MS_QUALITY_NONE;193194memset(&desc, 0, sizeof(desc));195surface = CALLOC_STRUCT(vmw_svga_winsys_surface);196if(!surface)197goto no_surface;198199pipe_reference_init(&surface->refcnt, 1);200p_atomic_set(&surface->validated, 0);201surface->screen = vws;202(void) mtx_init(&surface->mutex, mtx_plain);203surface->shared = !!(usage & SVGA_SURFACE_USAGE_SHARED);204provider = (surface->shared) ? vws->pools.gmr : vws->pools.mob_fenced;205206/*207* When multisampling is not supported sample count received is 0,208* otherwise should have a valid sample count.209*/210if ((flags & SVGA3D_SURFACE_MULTISAMPLE) != 0) {211if (sampleCount == 0)212goto no_sid;213num_samples = sampleCount;214multisample_pattern = SVGA3D_MS_PATTERN_STANDARD;215quality_level = SVGA3D_MS_QUALITY_FULL;216}217218/*219* Used for the backing buffer GB surfaces, and to approximate220* when to flush on non-GB hosts.221*/222buffer_size = svga3dsurface_get_serialized_size_extended(format, size,223numMipLevels,224numLayers,225num_samples);226if (flags & SVGA3D_SURFACE_BIND_STREAM_OUTPUT)227buffer_size += sizeof(SVGA3dDXSOState);228229if (buffer_size > vws->ioctl.max_texture_size) {230goto no_sid;231}232233if (sws->have_gb_objects) {234SVGAGuestPtr ptr = {0,0};235236/*237* If the backing buffer size is small enough, try to allocate a238* buffer out of the buffer cache. Otherwise, let the kernel allocate239* a suitable buffer for us.240*/241if (buffer_size < VMW_TRY_CACHED_SIZE && !surface->shared) {242struct pb_buffer *pb_buf;243244surface->size = buffer_size;245desc.pb_desc.alignment = 4096;246desc.pb_desc.usage = 0;247pb_buf = provider->create_buffer(provider, buffer_size, &desc.pb_desc);248surface->buf = vmw_svga_winsys_buffer_wrap(pb_buf);249if (surface->buf && !vmw_gmr_bufmgr_region_ptr(pb_buf, &ptr))250assert(0);251}252253surface->sid = vmw_ioctl_gb_surface_create(vws, flags, format, usage,254size, numLayers,255numMipLevels, sampleCount,256ptr.gmrId,257multisample_pattern,258quality_level,259surface->buf ? NULL :260&desc.region);261262if (surface->sid == SVGA3D_INVALID_ID) {263if (surface->buf == NULL) {264goto no_sid;265} else {266/*267* Kernel refused to allocate a surface for us.268* Perhaps something was wrong with our buffer?269* This is really a guard against future new size requirements270* on the backing buffers.271*/272vmw_svga_winsys_buffer_destroy(sws, surface->buf);273surface->buf = NULL;274surface->sid = vmw_ioctl_gb_surface_create(vws, flags, format, usage,275size, numLayers,276numMipLevels, sampleCount,2770, multisample_pattern,278quality_level,279&desc.region);280if (surface->sid == SVGA3D_INVALID_ID)281goto no_sid;282}283}284285/*286* If the kernel created the buffer for us, wrap it into a287* vmw_svga_winsys_buffer.288*/289if (surface->buf == NULL) {290struct pb_buffer *pb_buf;291292surface->size = vmw_region_size(desc.region);293desc.pb_desc.alignment = 4096;294desc.pb_desc.usage = VMW_BUFFER_USAGE_SHARED;295pb_buf = provider->create_buffer(provider, surface->size,296&desc.pb_desc);297surface->buf = vmw_svga_winsys_buffer_wrap(pb_buf);298if (surface->buf == NULL) {299vmw_ioctl_region_destroy(desc.region);300vmw_ioctl_surface_destroy(vws, surface->sid);301goto no_sid;302}303}304} else {305/* Legacy surface only support 32-bit svga3d flags */306surface->sid = vmw_ioctl_surface_create(vws, (SVGA3dSurface1Flags)flags,307format, usage, size, numLayers,308numMipLevels, sampleCount);309if(surface->sid == SVGA3D_INVALID_ID)310goto no_sid;311312/* Best estimate for surface size, used for early flushing. */313surface->size = buffer_size;314surface->buf = NULL;315}316317return svga_winsys_surface(surface);318319no_sid:320if (surface->buf)321vmw_svga_winsys_buffer_destroy(sws, surface->buf);322323FREE(surface);324no_surface:325return NULL;326}327328static boolean329vmw_svga_winsys_surface_can_create(struct svga_winsys_screen *sws,330SVGA3dSurfaceFormat format,331SVGA3dSize size,332uint32 numLayers,333uint32 numMipLevels,334uint32 numSamples)335{336struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);337uint32_t buffer_size;338339buffer_size = svga3dsurface_get_serialized_size(format, size,340numMipLevels,341numLayers);342if (numSamples > 1)343buffer_size *= numSamples;344345if (buffer_size > vws->ioctl.max_texture_size) {346return FALSE;347}348return TRUE;349}350351352static boolean353vmw_svga_winsys_surface_is_flushed(struct svga_winsys_screen *sws,354struct svga_winsys_surface *surface)355{356struct vmw_svga_winsys_surface *vsurf = vmw_svga_winsys_surface(surface);357return (p_atomic_read(&vsurf->validated) == 0);358}359360361static void362vmw_svga_winsys_surface_ref(struct svga_winsys_screen *sws,363struct svga_winsys_surface **pDst,364struct svga_winsys_surface *src)365{366struct vmw_svga_winsys_surface *d_vsurf = vmw_svga_winsys_surface(*pDst);367struct vmw_svga_winsys_surface *s_vsurf = vmw_svga_winsys_surface(src);368369vmw_svga_winsys_surface_reference(&d_vsurf, s_vsurf);370*pDst = svga_winsys_surface(d_vsurf);371}372373374static void375vmw_svga_winsys_destroy(struct svga_winsys_screen *sws)376{377struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);378379vmw_winsys_destroy(vws);380}381382383static SVGA3dHardwareVersion384vmw_svga_winsys_get_hw_version(struct svga_winsys_screen *sws)385{386struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);387388if (sws->have_gb_objects)389return SVGA3D_HWVERSION_WS8_B1;390391return (SVGA3dHardwareVersion) vws->ioctl.hwversion;392}393394395static boolean396vmw_svga_winsys_get_cap(struct svga_winsys_screen *sws,397SVGA3dDevCapIndex index,398SVGA3dDevCapResult *result)399{400struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);401402if (index > vws->ioctl.num_cap_3d ||403index >= SVGA3D_DEVCAP_MAX ||404!vws->ioctl.cap_3d[index].has_cap)405return FALSE;406407*result = vws->ioctl.cap_3d[index].result;408return TRUE;409}410411struct svga_winsys_gb_shader *412vmw_svga_winsys_shader_create(struct svga_winsys_screen *sws,413SVGA3dShaderType type,414const uint32 *bytecode,415uint32 bytecodeLen)416{417struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);418struct vmw_svga_winsys_shader *shader;419void *code;420421shader = CALLOC_STRUCT(vmw_svga_winsys_shader);422if(!shader)423goto out_no_shader;424425pipe_reference_init(&shader->refcnt, 1);426p_atomic_set(&shader->validated, 0);427shader->screen = vws;428shader->buf = vmw_svga_winsys_buffer_create(sws, 64,429SVGA_BUFFER_USAGE_SHADER,430bytecodeLen);431if (!shader->buf)432goto out_no_buf;433434code = vmw_svga_winsys_buffer_map(sws, shader->buf, PIPE_MAP_WRITE);435if (!code)436goto out_no_buf;437438memcpy(code, bytecode, bytecodeLen);439vmw_svga_winsys_buffer_unmap(sws, shader->buf);440441if (!sws->have_vgpu10) {442shader->shid = vmw_ioctl_shader_create(vws, type, bytecodeLen);443if (shader->shid == SVGA3D_INVALID_ID)444goto out_no_shid;445}446447return svga_winsys_shader(shader);448449out_no_shid:450vmw_svga_winsys_buffer_destroy(sws, shader->buf);451out_no_buf:452FREE(shader);453out_no_shader:454return NULL;455}456457void458vmw_svga_winsys_shader_destroy(struct svga_winsys_screen *sws,459struct svga_winsys_gb_shader *shader)460{461struct vmw_svga_winsys_shader *d_shader =462vmw_svga_winsys_shader(shader);463464vmw_svga_winsys_shader_reference(&d_shader, NULL);465}466467static void468vmw_svga_winsys_stats_inc(enum svga_stats_count index)469{470}471472static void473vmw_svga_winsys_stats_time_push(enum svga_stats_time index,474struct svga_winsys_stats_timeframe *tf)475{476}477478static void479vmw_svga_winsys_stats_time_pop()480{481}482483boolean484vmw_winsys_screen_init_svga(struct vmw_winsys_screen *vws)485{486vws->base.destroy = vmw_svga_winsys_destroy;487vws->base.get_hw_version = vmw_svga_winsys_get_hw_version;488vws->base.get_cap = vmw_svga_winsys_get_cap;489vws->base.context_create = vmw_svga_winsys_context_create;490vws->base.surface_create = vmw_svga_winsys_surface_create;491vws->base.surface_is_flushed = vmw_svga_winsys_surface_is_flushed;492vws->base.surface_reference = vmw_svga_winsys_surface_ref;493vws->base.surface_can_create = vmw_svga_winsys_surface_can_create;494vws->base.buffer_create = vmw_svga_winsys_buffer_create;495vws->base.buffer_map = vmw_svga_winsys_buffer_map;496vws->base.buffer_unmap = vmw_svga_winsys_buffer_unmap;497vws->base.buffer_destroy = vmw_svga_winsys_buffer_destroy;498vws->base.surface_init = vmw_svga_winsys_surface_init;499vws->base.fence_reference = vmw_svga_winsys_fence_reference;500vws->base.fence_signalled = vmw_svga_winsys_fence_signalled;501vws->base.shader_create = vmw_svga_winsys_shader_create;502vws->base.shader_destroy = vmw_svga_winsys_shader_destroy;503vws->base.fence_finish = vmw_svga_winsys_fence_finish;504vws->base.fence_get_fd = vmw_svga_winsys_fence_get_fd;505vws->base.fence_create_fd = vmw_svga_winsys_fence_create_fd;506vws->base.fence_server_sync = vmw_svga_winsys_fence_server_sync;507508vws->base.query_create = vmw_svga_winsys_query_create;509vws->base.query_init = vmw_svga_winsys_query_init;510vws->base.query_destroy = vmw_svga_winsys_query_destroy;511vws->base.query_get_result = vmw_svga_winsys_query_get_result;512513vws->base.stats_inc = vmw_svga_winsys_stats_inc;514vws->base.stats_time_push = vmw_svga_winsys_stats_time_push;515vws->base.stats_time_pop = vmw_svga_winsys_stats_time_pop;516517vws->base.host_log = vmw_svga_winsys_host_log;518519return TRUE;520}521522523524525