Path: blob/21.2-virgl/src/gallium/drivers/tegra/tegra_screen.c
4570 views
/*1* Copyright © 2014-2018 NVIDIA Corporation2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING19* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS20* IN THE SOFTWARE.21*/2223#include <errno.h>24#include <fcntl.h>25#include <inttypes.h>26#include <stdio.h>2728#include <sys/stat.h>2930#include "drm-uapi/drm_fourcc.h"31#include "drm-uapi/tegra_drm.h"32#include <xf86drm.h>3334#include "loader/loader.h"35#include "pipe/p_state.h"36#include "util/u_debug.h"37#include "util/format/u_format.h"38#include "util/u_inlines.h"3940#include "frontend/drm_driver.h"4142#include "nouveau/drm/nouveau_drm_public.h"4344#include "tegra_context.h"45#include "tegra_resource.h"46#include "tegra_screen.h"4748static void tegra_screen_destroy(struct pipe_screen *pscreen)49{50struct tegra_screen *screen = to_tegra_screen(pscreen);5152screen->gpu->destroy(screen->gpu);53free(pscreen);54}5556static const char *57tegra_screen_get_name(struct pipe_screen *pscreen)58{59return "tegra";60}6162static const char *63tegra_screen_get_vendor(struct pipe_screen *pscreen)64{65return "NVIDIA";66}6768static const char *69tegra_screen_get_device_vendor(struct pipe_screen *pscreen)70{71return "NVIDIA";72}7374static int75tegra_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param)76{77struct tegra_screen *screen = to_tegra_screen(pscreen);7879return screen->gpu->get_param(screen->gpu, param);80}8182static float83tegra_screen_get_paramf(struct pipe_screen *pscreen, enum pipe_capf param)84{85struct tegra_screen *screen = to_tegra_screen(pscreen);8687return screen->gpu->get_paramf(screen->gpu, param);88}8990static int91tegra_screen_get_shader_param(struct pipe_screen *pscreen, unsigned shader,92enum pipe_shader_cap param)93{94struct tegra_screen *screen = to_tegra_screen(pscreen);9596return screen->gpu->get_shader_param(screen->gpu, shader, param);97}9899static int100tegra_screen_get_video_param(struct pipe_screen *pscreen,101enum pipe_video_profile profile,102enum pipe_video_entrypoint entrypoint,103enum pipe_video_cap param)104{105struct tegra_screen *screen = to_tegra_screen(pscreen);106107return screen->gpu->get_video_param(screen->gpu, profile, entrypoint,108param);109}110111static int112tegra_screen_get_compute_param(struct pipe_screen *pscreen,113enum pipe_shader_ir ir_type,114enum pipe_compute_cap param,115void *retp)116{117struct tegra_screen *screen = to_tegra_screen(pscreen);118119return screen->gpu->get_compute_param(screen->gpu, ir_type, param,120retp);121}122123static uint64_t124tegra_screen_get_timestamp(struct pipe_screen *pscreen)125{126struct tegra_screen *screen = to_tegra_screen(pscreen);127128return screen->gpu->get_timestamp(screen->gpu);129}130131static bool132tegra_screen_is_format_supported(struct pipe_screen *pscreen,133enum pipe_format format,134enum pipe_texture_target target,135unsigned sample_count,136unsigned storage_sample_count,137unsigned usage)138{139struct tegra_screen *screen = to_tegra_screen(pscreen);140141return screen->gpu->is_format_supported(screen->gpu, format, target,142sample_count, storage_sample_count,143usage);144}145146static bool147tegra_screen_is_video_format_supported(struct pipe_screen *pscreen,148enum pipe_format format,149enum pipe_video_profile profile,150enum pipe_video_entrypoint entrypoint)151{152struct tegra_screen *screen = to_tegra_screen(pscreen);153154return screen->gpu->is_video_format_supported(screen->gpu, format, profile,155entrypoint);156}157158static bool159tegra_screen_can_create_resource(struct pipe_screen *pscreen,160const struct pipe_resource *template)161{162struct tegra_screen *screen = to_tegra_screen(pscreen);163164return screen->gpu->can_create_resource(screen->gpu, template);165}166167static int tegra_screen_import_resource(struct tegra_screen *screen,168struct tegra_resource *resource)169{170struct winsys_handle handle;171bool status;172int fd, err;173174memset(&handle, 0, sizeof(handle));175handle.modifier = DRM_FORMAT_MOD_INVALID;176handle.type = WINSYS_HANDLE_TYPE_FD;177178status = screen->gpu->resource_get_handle(screen->gpu, NULL, resource->gpu,179&handle, 0);180if (!status)181return -EINVAL;182183assert(handle.modifier != DRM_FORMAT_MOD_INVALID);184185if (handle.modifier == DRM_FORMAT_MOD_INVALID) {186close(handle.handle);187return -EINVAL;188}189190resource->modifier = handle.modifier;191resource->stride = handle.stride;192fd = handle.handle;193194err = drmPrimeFDToHandle(screen->fd, fd, &resource->handle);195if (err < 0)196err = -errno;197198close(fd);199200return err;201}202203static struct pipe_resource *204tegra_screen_resource_create(struct pipe_screen *pscreen,205const struct pipe_resource *template)206{207struct tegra_screen *screen = to_tegra_screen(pscreen);208uint64_t modifier = DRM_FORMAT_MOD_INVALID;209struct tegra_resource *resource;210int err;211212resource = calloc(1, sizeof(*resource));213if (!resource)214return NULL;215216/*217* Applications that create scanout resources without modifiers are very218* unlikely to support modifiers at all. In that case the resources need219* to be created with a pitch-linear layout so that they can be properly220* shared with scanout hardware.221*222* Technically it is possible for applications to create resources without223* specifying a modifier but still query the modifier associated with the224* resource (e.g. using gbm_bo_get_modifier()) before handing it to the225* framebuffer creation API (such as the DRM_IOCTL_MODE_ADDFB2 IOCTL).226*/227if (template->bind & PIPE_BIND_SCANOUT)228modifier = DRM_FORMAT_MOD_LINEAR;229230resource->gpu = screen->gpu->resource_create_with_modifiers(screen->gpu,231template,232&modifier, 1);233if (!resource->gpu)234goto free;235236/* import scanout buffers for display */237if (template->bind & PIPE_BIND_SCANOUT) {238err = tegra_screen_import_resource(screen, resource);239if (err < 0)240goto destroy;241}242243memcpy(&resource->base, resource->gpu, sizeof(*resource->gpu));244pipe_reference_init(&resource->base.reference, 1);245resource->base.screen = &screen->base;246247return &resource->base;248249destroy:250screen->gpu->resource_destroy(screen->gpu, resource->gpu);251free:252free(resource);253return NULL;254}255256/* XXX */257static struct pipe_resource *258tegra_screen_resource_create_front(struct pipe_screen *pscreen,259const struct pipe_resource *template,260const void *map_front_private)261{262struct tegra_screen *screen = to_tegra_screen(pscreen);263struct pipe_resource *resource;264265resource = screen->gpu->resource_create_front(screen->gpu, template,266map_front_private);267if (resource)268resource->screen = pscreen;269270return resource;271}272273static struct pipe_resource *274tegra_screen_resource_from_handle(struct pipe_screen *pscreen,275const struct pipe_resource *template,276struct winsys_handle *handle,277unsigned usage)278{279struct tegra_screen *screen = to_tegra_screen(pscreen);280struct tegra_resource *resource;281282resource = calloc(1, sizeof(*resource));283if (!resource)284return NULL;285286resource->gpu = screen->gpu->resource_from_handle(screen->gpu, template,287handle, usage);288if (!resource->gpu) {289free(resource);290return NULL;291}292293memcpy(&resource->base, resource->gpu, sizeof(*resource->gpu));294pipe_reference_init(&resource->base.reference, 1);295resource->base.screen = &screen->base;296297return &resource->base;298}299300/* XXX */301static struct pipe_resource *302tegra_screen_resource_from_user_memory(struct pipe_screen *pscreen,303const struct pipe_resource *template,304void *buffer)305{306struct tegra_screen *screen = to_tegra_screen(pscreen);307struct pipe_resource *resource;308309resource = screen->gpu->resource_from_user_memory(screen->gpu, template,310buffer);311if (resource)312resource->screen = pscreen;313314return resource;315}316317static bool318tegra_screen_resource_get_handle(struct pipe_screen *pscreen,319struct pipe_context *pcontext,320struct pipe_resource *presource,321struct winsys_handle *handle,322unsigned usage)323{324struct tegra_resource *resource = to_tegra_resource(presource);325struct tegra_context *context = to_tegra_context(pcontext);326struct tegra_screen *screen = to_tegra_screen(pscreen);327bool ret = true;328329/*330* Assume that KMS handles for scanout resources will only ever be used331* to pass buffers into Tegra DRM for display. In all other cases, return332* the Nouveau handle, assuming they will be used for sharing in DRI2/3.333*/334if (handle->type == WINSYS_HANDLE_TYPE_KMS &&335presource->bind & PIPE_BIND_SCANOUT) {336handle->modifier = resource->modifier;337handle->handle = resource->handle;338handle->stride = resource->stride;339} else {340ret = screen->gpu->resource_get_handle(screen->gpu,341context ? context->gpu : NULL,342resource->gpu, handle, usage);343}344345return ret;346}347348static void349tegra_screen_resource_destroy(struct pipe_screen *pscreen,350struct pipe_resource *presource)351{352struct tegra_resource *resource = to_tegra_resource(presource);353354pipe_resource_reference(&resource->gpu, NULL);355free(resource);356}357358static void359tegra_screen_flush_frontbuffer(struct pipe_screen *pscreen,360struct pipe_context *pcontext,361struct pipe_resource *resource,362unsigned int level,363unsigned int layer,364void *winsys_drawable_handle,365struct pipe_box *box)366{367struct tegra_screen *screen = to_tegra_screen(pscreen);368struct tegra_context *context = to_tegra_context(pcontext);369370screen->gpu->flush_frontbuffer(screen->gpu,371context ? context->gpu : NULL,372resource, level, layer,373winsys_drawable_handle, box);374}375376static void377tegra_screen_fence_reference(struct pipe_screen *pscreen,378struct pipe_fence_handle **ptr,379struct pipe_fence_handle *fence)380{381struct tegra_screen *screen = to_tegra_screen(pscreen);382383screen->gpu->fence_reference(screen->gpu, ptr, fence);384}385386static bool387tegra_screen_fence_finish(struct pipe_screen *pscreen,388struct pipe_context *pcontext,389struct pipe_fence_handle *fence,390uint64_t timeout)391{392struct tegra_context *context = to_tegra_context(pcontext);393struct tegra_screen *screen = to_tegra_screen(pscreen);394395return screen->gpu->fence_finish(screen->gpu,396context ? context->gpu : NULL,397fence, timeout);398}399400static int401tegra_screen_fence_get_fd(struct pipe_screen *pscreen,402struct pipe_fence_handle *fence)403{404struct tegra_screen *screen = to_tegra_screen(pscreen);405406return screen->gpu->fence_get_fd(screen->gpu, fence);407}408409static int410tegra_screen_get_driver_query_info(struct pipe_screen *pscreen,411unsigned int index,412struct pipe_driver_query_info *info)413{414struct tegra_screen *screen = to_tegra_screen(pscreen);415416return screen->gpu->get_driver_query_info(screen->gpu, index, info);417}418419static int420tegra_screen_get_driver_query_group_info(struct pipe_screen *pscreen,421unsigned int index,422struct pipe_driver_query_group_info *info)423{424struct tegra_screen *screen = to_tegra_screen(pscreen);425426return screen->gpu->get_driver_query_group_info(screen->gpu, index, info);427}428429static void430tegra_screen_query_memory_info(struct pipe_screen *pscreen,431struct pipe_memory_info *info)432{433struct tegra_screen *screen = to_tegra_screen(pscreen);434435screen->gpu->query_memory_info(screen->gpu, info);436}437438static const void *439tegra_screen_get_compiler_options(struct pipe_screen *pscreen,440enum pipe_shader_ir ir,441unsigned int shader)442{443struct tegra_screen *screen = to_tegra_screen(pscreen);444const void *options = NULL;445446if (screen->gpu->get_compiler_options)447options = screen->gpu->get_compiler_options(screen->gpu, ir, shader);448449return options;450}451452static struct disk_cache *453tegra_screen_get_disk_shader_cache(struct pipe_screen *pscreen)454{455struct tegra_screen *screen = to_tegra_screen(pscreen);456457return screen->gpu->get_disk_shader_cache(screen->gpu);458}459460static struct pipe_resource *461tegra_screen_resource_create_with_modifiers(struct pipe_screen *pscreen,462const struct pipe_resource *template,463const uint64_t *modifiers,464int count)465{466struct tegra_screen *screen = to_tegra_screen(pscreen);467struct pipe_resource tmpl = *template;468struct tegra_resource *resource;469int err;470471resource = calloc(1, sizeof(*resource));472if (!resource)473return NULL;474475/*476* Assume that resources created with modifiers will always be used for477* scanout. This is necessary because some of the APIs that are used to478* create resources with modifiers (e.g. gbm_bo_create_with_modifiers())479* can't pass along usage information. Adding that capability might be480* worth adding to remove this ambiguity. Not all future use-cases that481* involve modifiers may always be targetting scanout hardware.482*/483tmpl.bind |= PIPE_BIND_SCANOUT;484485resource->gpu = screen->gpu->resource_create_with_modifiers(screen->gpu,486&tmpl,487modifiers,488count);489if (!resource->gpu)490goto free;491492err = tegra_screen_import_resource(screen, resource);493if (err < 0)494goto destroy;495496memcpy(&resource->base, resource->gpu, sizeof(*resource->gpu));497pipe_reference_init(&resource->base.reference, 1);498resource->base.screen = &screen->base;499500return &resource->base;501502destroy:503screen->gpu->resource_destroy(screen->gpu, resource->gpu);504free:505free(resource);506return NULL;507}508509static void tegra_screen_query_dmabuf_modifiers(struct pipe_screen *pscreen,510enum pipe_format format,511int max, uint64_t *modifiers,512unsigned int *external_only,513int *count)514{515struct tegra_screen *screen = to_tegra_screen(pscreen);516517screen->gpu->query_dmabuf_modifiers(screen->gpu, format, max, modifiers,518external_only, count);519}520521static bool522tegra_screen_is_dmabuf_modifier_supported(struct pipe_screen *pscreen,523uint64_t modifier,524enum pipe_format format,525bool *external_only)526{527struct tegra_screen *screen = to_tegra_screen(pscreen);528529return screen->gpu->is_dmabuf_modifier_supported(screen->gpu, modifier,530format, external_only);531}532533static unsigned int534tegra_screen_get_dmabuf_modifier_planes(struct pipe_screen *pscreen,535uint64_t modifier,536enum pipe_format format)537{538struct tegra_screen *screen = to_tegra_screen(pscreen);539540return screen->gpu->get_dmabuf_modifier_planes ?541screen->gpu->get_dmabuf_modifier_planes(screen->gpu, modifier, format) :542util_format_get_num_planes(format);543}544545static struct pipe_memory_object *546tegra_screen_memobj_create_from_handle(struct pipe_screen *pscreen,547struct winsys_handle *handle,548bool dedicated)549{550struct tegra_screen *screen = to_tegra_screen(pscreen);551552return screen->gpu->memobj_create_from_handle(screen->gpu, handle,553dedicated);554}555556struct pipe_screen *557tegra_screen_create(int fd)558{559struct tegra_screen *screen;560561screen = calloc(1, sizeof(*screen));562if (!screen)563return NULL;564565screen->fd = fd;566567screen->gpu_fd = loader_open_render_node("nouveau");568if (screen->gpu_fd < 0) {569if (errno != ENOENT)570fprintf(stderr, "failed to open GPU device: %s\n", strerror(errno));571572free(screen);573return NULL;574}575576screen->gpu = nouveau_drm_screen_create(screen->gpu_fd);577if (!screen->gpu) {578fprintf(stderr, "failed to create GPU screen\n");579close(screen->gpu_fd);580free(screen);581return NULL;582}583584screen->base.destroy = tegra_screen_destroy;585screen->base.get_name = tegra_screen_get_name;586screen->base.get_vendor = tegra_screen_get_vendor;587screen->base.get_device_vendor = tegra_screen_get_device_vendor;588screen->base.get_param = tegra_screen_get_param;589screen->base.get_paramf = tegra_screen_get_paramf;590screen->base.get_shader_param = tegra_screen_get_shader_param;591screen->base.get_video_param = tegra_screen_get_video_param;592screen->base.get_compute_param = tegra_screen_get_compute_param;593screen->base.get_timestamp = tegra_screen_get_timestamp;594screen->base.context_create = tegra_screen_context_create;595screen->base.is_format_supported = tegra_screen_is_format_supported;596screen->base.is_video_format_supported = tegra_screen_is_video_format_supported;597598/* allow fallback implementation if GPU driver doesn't implement it */599if (screen->gpu->can_create_resource)600screen->base.can_create_resource = tegra_screen_can_create_resource;601602screen->base.resource_create = tegra_screen_resource_create;603screen->base.resource_create_front = tegra_screen_resource_create_front;604screen->base.resource_from_handle = tegra_screen_resource_from_handle;605screen->base.resource_from_user_memory = tegra_screen_resource_from_user_memory;606screen->base.resource_get_handle = tegra_screen_resource_get_handle;607screen->base.resource_destroy = tegra_screen_resource_destroy;608609screen->base.flush_frontbuffer = tegra_screen_flush_frontbuffer;610screen->base.fence_reference = tegra_screen_fence_reference;611screen->base.fence_finish = tegra_screen_fence_finish;612screen->base.fence_get_fd = tegra_screen_fence_get_fd;613614screen->base.get_driver_query_info = tegra_screen_get_driver_query_info;615screen->base.get_driver_query_group_info = tegra_screen_get_driver_query_group_info;616screen->base.query_memory_info = tegra_screen_query_memory_info;617618screen->base.get_compiler_options = tegra_screen_get_compiler_options;619screen->base.get_disk_shader_cache = tegra_screen_get_disk_shader_cache;620621screen->base.resource_create_with_modifiers = tegra_screen_resource_create_with_modifiers;622screen->base.query_dmabuf_modifiers = tegra_screen_query_dmabuf_modifiers;623screen->base.is_dmabuf_modifier_supported = tegra_screen_is_dmabuf_modifier_supported;624screen->base.get_dmabuf_modifier_planes = tegra_screen_get_dmabuf_modifier_planes;625screen->base.memobj_create_from_handle = tegra_screen_memobj_create_from_handle;626627return &screen->base;628}629630631