1/* 2 * Copyright (c) 2015 Etnaviv Project 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sub license, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the 12 * next paragraph) shall be included in all copies or substantial portions 13 * of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 * 23 * Authors: 24 * Christian Gmeiner <christian.gmeiner@gmail.com> 25 */ 26 27#include <sys/stat.h> 28 29#include "util/u_hash_table.h" 30#include "util/u_memory.h" 31 32#include "etnaviv/etnaviv_screen.h" 33#include "etnaviv/hw/common.xml.h" 34#include "etnaviv_drm_public.h" 35 36#include <stdio.h> 37 38static struct pipe_screen * 39screen_create(struct renderonly *ro) 40{ 41 struct etna_device *dev; 42 struct etna_gpu *gpu; 43 uint64_t val; 44 int i; 45 46 dev = etna_device_new_dup(ro->gpu_fd); 47 if (!dev) { 48 fprintf(stderr, "Error creating device\n"); 49 return NULL; 50 } 51 52 for (i = 0;; i++) { 53 gpu = etna_gpu_new(dev, i); 54 if (!gpu) { 55 fprintf(stderr, "Error creating gpu\n"); 56 return NULL; 57 } 58 59 /* Look for a 3D capable GPU */ 60 int ret = etna_gpu_get_param(gpu, ETNA_GPU_FEATURES_0, &val); 61 if (ret == 0 && (val & chipFeatures_PIPE_3D)) 62 break; 63 64 etna_gpu_del(gpu); 65 } 66 67 return etna_screen_create(dev, gpu, ro); 68} 69 70static struct util_hash_table *etna_tab = NULL; 71 72static mtx_t etna_screen_mutex = _MTX_INITIALIZER_NP; 73 74static void 75etna_drm_screen_destroy(struct pipe_screen *pscreen) 76{ 77 struct etna_screen *screen = etna_screen(pscreen); 78 boolean destroy; 79 80 mtx_lock(&etna_screen_mutex); 81 destroy = --screen->refcnt == 0; 82 if (destroy) { 83 int fd = etna_device_fd(screen->dev); 84 util_hash_table_remove(etna_tab, intptr_to_pointer(fd)); 85 } 86 mtx_unlock(&etna_screen_mutex); 87 88 if (destroy) { 89 pscreen->destroy = screen->winsys_priv; 90 pscreen->destroy(pscreen); 91 } 92} 93 94static unsigned hash_fd(void *key) 95{ 96 int fd = pointer_to_intptr(key); 97 struct stat stat; 98 99 fstat(fd, &stat); 100 101 return stat.st_dev ^ stat.st_ino ^ stat.st_rdev; 102} 103 104static int compare_fd(void *key1, void *key2) 105{ 106 int fd1 = pointer_to_intptr(key1); 107 int fd2 = pointer_to_intptr(key2); 108 struct stat stat1, stat2; 109 110 fstat(fd1, &stat1); 111 fstat(fd2, &stat2); 112 113 return stat1.st_dev != stat2.st_dev || 114 stat1.st_ino != stat2.st_ino || 115 stat1.st_rdev != stat2.st_rdev; 116} 117 118struct pipe_screen * 119etna_drm_screen_create_renderonly(struct renderonly *ro) 120{ 121 struct pipe_screen *pscreen = NULL; 122 123 mtx_lock(&etna_screen_mutex); 124 if (!etna_tab) { 125 etna_tab = util_hash_table_create(hash_fd, compare_fd); 126 if (!etna_tab) 127 goto unlock; 128 } 129 130 pscreen = util_hash_table_get(etna_tab, intptr_to_pointer(ro->gpu_fd)); 131 if (pscreen) { 132 etna_screen(pscreen)->refcnt++; 133 } else { 134 pscreen = screen_create(ro); 135 if (pscreen) { 136 int fd = etna_device_fd(etna_screen(pscreen)->dev); 137 util_hash_table_set(etna_tab, intptr_to_pointer(fd), pscreen); 138 139 /* Bit of a hack, to avoid circular linkage dependency, 140 * ie. pipe driver having to call in to winsys, we 141 * override the pipe drivers screen->destroy() */ 142 etna_screen(pscreen)->winsys_priv = pscreen->destroy; 143 pscreen->destroy = etna_drm_screen_destroy; 144 } 145 } 146 147unlock: 148 mtx_unlock(&etna_screen_mutex); 149 return pscreen; 150} 151 152struct pipe_screen * 153etna_drm_screen_create(int fd) 154{ 155 struct renderonly ro = { 156 .create_for_resource = renderonly_create_gpu_import_for_resource, 157 .kms_fd = -1, 158 .gpu_fd = fd 159 }; 160 161 return etna_drm_screen_create_renderonly(&ro); 162} 163