nouveau_screen.c revision ed7f73e161b93b4a83bb6ad6b6aa6cfcb65dc4b0
1#include "pipe/p_defines.h" 2#include "pipe/p_screen.h" 3#include "pipe/p_state.h" 4 5#include "util/u_memory.h" 6#include "util/u_inlines.h" 7#include "util/u_format.h" 8 9#include <stdio.h> 10#include <errno.h> 11 12#include "nouveau/nouveau_bo.h" 13#include "nouveau_winsys.h" 14#include "nouveau_screen.h" 15 16/* XXX this should go away */ 17#include "state_tracker/drm_api.h" 18 19static const char * 20nouveau_screen_get_name(struct pipe_screen *pscreen) 21{ 22 struct nouveau_device *dev = nouveau_screen(pscreen)->device; 23 static char buffer[128]; 24 25 snprintf(buffer, sizeof(buffer), "NV%02X", dev->chipset); 26 return buffer; 27} 28 29static const char * 30nouveau_screen_get_vendor(struct pipe_screen *pscreen) 31{ 32 return "nouveau"; 33} 34 35static struct pipe_buffer * 36nouveau_screen_bo_skel(struct pipe_screen *pscreen, struct nouveau_bo *bo, 37 unsigned alignment, unsigned usage, unsigned size) 38{ 39 struct pipe_buffer *pb; 40 41 pb = CALLOC(1, sizeof(struct pipe_buffer)+sizeof(struct nouveau_bo *)); 42 if (!pb) { 43 nouveau_bo_ref(NULL, &bo); 44 return NULL; 45 } 46 47 pipe_reference_init(&pb->reference, 1); 48 pb->screen = pscreen; 49 pb->alignment = alignment; 50 pb->usage = usage; 51 pb->size = size; 52 *(struct nouveau_bo **)(pb + 1) = bo; 53 return pb; 54} 55 56static struct pipe_buffer * 57nouveau_screen_bo_new(struct pipe_screen *pscreen, unsigned alignment, 58 unsigned usage, unsigned size) 59{ 60 struct nouveau_device *dev = nouveau_screen(pscreen)->device; 61 struct nouveau_bo *bo = NULL; 62 uint32_t flags = NOUVEAU_BO_MAP, tile_mode = 0, tile_flags = 0; 63 int ret; 64 65 if (usage & NOUVEAU_BUFFER_USAGE_TRANSFER) 66 flags |= NOUVEAU_BO_GART; 67 else 68 if (usage & PIPE_BUFFER_USAGE_VERTEX) { 69 if (pscreen->get_param(pscreen, NOUVEAU_CAP_HW_VTXBUF)) 70 flags |= NOUVEAU_BO_GART; 71 } else 72 if (usage & PIPE_BUFFER_USAGE_INDEX) { 73 if (pscreen->get_param(pscreen, NOUVEAU_CAP_HW_IDXBUF)) 74 flags |= NOUVEAU_BO_GART; 75 } 76 77 if (usage & PIPE_BUFFER_USAGE_PIXEL) { 78 if (usage & NOUVEAU_BUFFER_USAGE_TEXTURE) 79 flags |= NOUVEAU_BO_GART; 80 if (!(usage & PIPE_BUFFER_USAGE_CPU_READ_WRITE)) 81 flags |= NOUVEAU_BO_VRAM; 82 83 if (dev->chipset == 0x50 || dev->chipset >= 0x80) { 84 if (usage & NOUVEAU_BUFFER_USAGE_ZETA) 85 tile_flags = 0x2800; 86 else 87 tile_flags = 0x7000; 88 } 89 } 90 91 ret = nouveau_bo_new_tile(dev, flags, alignment, size, 92 tile_mode, tile_flags, &bo); 93 if (ret) 94 return NULL; 95 96 return nouveau_screen_bo_skel(pscreen, bo, alignment, usage, size); 97} 98 99static struct pipe_buffer * 100nouveau_screen_bo_user(struct pipe_screen *pscreen, void *ptr, unsigned bytes) 101{ 102 struct nouveau_device *dev = nouveau_screen(pscreen)->device; 103 struct nouveau_bo *bo = NULL; 104 int ret; 105 106 ret = nouveau_bo_user(dev, ptr, bytes, &bo); 107 if (ret) 108 return NULL; 109 110 return nouveau_screen_bo_skel(pscreen, bo, 0, 0, bytes); 111} 112 113static inline uint32_t 114nouveau_screen_map_flags(unsigned pipe) 115{ 116 uint32_t flags = 0; 117 118 if (pipe & PIPE_BUFFER_USAGE_CPU_READ) 119 flags |= NOUVEAU_BO_RD; 120 if (pipe & PIPE_BUFFER_USAGE_CPU_WRITE) 121 flags |= NOUVEAU_BO_WR; 122 if (pipe & PIPE_BUFFER_USAGE_DISCARD) 123 flags |= NOUVEAU_BO_INVAL; 124 if (pipe & PIPE_BUFFER_USAGE_DONTBLOCK) 125 flags |= NOUVEAU_BO_NOWAIT; 126 else 127 if (pipe & PIPE_BUFFER_USAGE_UNSYNCHRONIZED) 128 flags |= NOUVEAU_BO_NOSYNC; 129 130 return flags; 131} 132 133static void * 134nouveau_screen_bo_map(struct pipe_screen *pscreen, struct pipe_buffer *pb, 135 unsigned usage) 136{ 137 struct nouveau_bo *bo = nouveau_bo(pb); 138 struct nouveau_screen *nscreen = nouveau_screen(pscreen); 139 int ret; 140 141 if (nscreen->pre_pipebuffer_map_callback) { 142 ret = nscreen->pre_pipebuffer_map_callback(pscreen, pb, usage); 143 if (ret) { 144 debug_printf("pre_pipebuffer_map_callback failed %d\n", 145 ret); 146 return NULL; 147 } 148 } 149 150 ret = nouveau_bo_map(bo, nouveau_screen_map_flags(usage)); 151 if (ret) { 152 debug_printf("map failed: %d\n", ret); 153 return NULL; 154 } 155 156 return bo->map; 157} 158 159static void * 160nouveau_screen_bo_map_range(struct pipe_screen *pscreen, struct pipe_buffer *pb, 161 unsigned offset, unsigned length, unsigned usage) 162{ 163 struct nouveau_bo *bo = nouveau_bo(pb); 164 struct nouveau_screen *nscreen = nouveau_screen(pscreen); 165 uint32_t flags = nouveau_screen_map_flags(usage); 166 int ret; 167 168 if (nscreen->pre_pipebuffer_map_callback) { 169 ret = nscreen->pre_pipebuffer_map_callback(pscreen, pb, usage); 170 if (ret) { 171 debug_printf("pre_pipebuffer_map_callback failed %d\n", 172 ret); 173 return NULL; 174 } 175 } 176 177 ret = nouveau_bo_map_range(bo, offset, length, flags); 178 if (ret) { 179 nouveau_bo_unmap(bo); 180 if (!(flags & NOUVEAU_BO_NOWAIT) || ret != -EBUSY) 181 debug_printf("map_range failed: %d\n", ret); 182 return NULL; 183 } 184 185 return (char *)bo->map - offset; /* why gallium? why? */ 186} 187 188static void 189nouveau_screen_bo_map_flush(struct pipe_screen *pscreen, struct pipe_buffer *pb, 190 unsigned offset, unsigned length) 191{ 192 struct nouveau_bo *bo = nouveau_bo(pb); 193 194 nouveau_bo_map_flush(bo, offset, length); 195} 196 197static void 198nouveau_screen_bo_unmap(struct pipe_screen *pscreen, struct pipe_buffer *pb) 199{ 200 struct nouveau_bo *bo = nouveau_bo(pb); 201 202 nouveau_bo_unmap(bo); 203} 204 205static void 206nouveau_screen_bo_del(struct pipe_buffer *pb) 207{ 208 struct nouveau_bo *bo = nouveau_bo(pb); 209 210 nouveau_bo_ref(NULL, &bo); 211 FREE(pb); 212} 213 214static void 215nouveau_screen_fence_ref(struct pipe_screen *pscreen, 216 struct pipe_fence_handle **ptr, 217 struct pipe_fence_handle *pfence) 218{ 219 *ptr = pfence; 220} 221 222static int 223nouveau_screen_fence_signalled(struct pipe_screen *screen, 224 struct pipe_fence_handle *pfence, 225 unsigned flags) 226{ 227 return 0; 228} 229 230static int 231nouveau_screen_fence_finish(struct pipe_screen *screen, 232 struct pipe_fence_handle *pfence, 233 unsigned flags) 234{ 235 return 0; 236} 237 238 239/* 240 * Both texture_{from|get}_handle use drm api defines directly which they 241 * shouldn't do. The problem is that from|get are pipe functions and as 242 * such they should be defined in the pipe level. If nouveau had a propper 243 * winsys interface we would have added from|get to that interface using 244 * the winsys_handle struct as done with other drivers. However this code 245 * calls directly into the libdrm_nouveau.so functions (nouveau_bo_*). So 246 * we need to translate the handle into something they understand. 247 */ 248static struct pipe_texture * 249nouveau_screen_texture_from_handle(struct pipe_screen *pscreen, 250 const struct pipe_texture *templ, 251 struct winsys_handle *whandle) 252{ 253 struct nouveau_device *dev = nouveau_screen(pscreen)->device; 254 struct pipe_texture *pt; 255 struct pipe_buffer *pb; 256 int ret; 257 258 pb = CALLOC(1, sizeof(struct pipe_buffer) + sizeof(struct nouveau_bo*)); 259 if (!pb) 260 return NULL; 261 262 ret = nouveau_bo_handle_ref(dev, whandle->handle, (struct nouveau_bo**)(pb+1)); 263 if (ret) { 264 debug_printf("%s: ref name 0x%08x failed with %d\n", 265 __func__, whandle->handle, ret); 266 FREE(pb); 267 return NULL; 268 } 269 270 pipe_reference_init(&pb->reference, 1); 271 pb->screen = pscreen; 272 pb->alignment = 0; 273 pb->usage = PIPE_BUFFER_USAGE_GPU_READ_WRITE | 274 PIPE_BUFFER_USAGE_CPU_READ_WRITE; 275 pb->size = nouveau_bo(pb)->size; 276 pt = nouveau_screen(pscreen)->texture_blanket(pscreen, templ, 277 &whandle->stride, pb); 278 pipe_buffer_reference(&pb, NULL); 279 return pt; 280} 281 282static boolean 283nouveau_screen_texture_get_handle(struct pipe_screen *pscreen, 284 struct pipe_texture *pt, 285 struct winsys_handle *whandle) 286{ 287 struct nouveau_miptree *mt = nouveau_miptree(pt); 288 289 if (!mt || !mt->bo) 290 return false; 291 292 whandle->stride = util_format_get_stride(mt->base.format, mt->base.width0); 293 294 if (whandle->type == DRM_API_HANDLE_TYPE_SHARED) { 295 return nouveau_bo_handle_get(mt->bo, &whandle->handle) == 0; 296 } else if (whandle->type == DRM_API_HANDLE_TYPE_KMS) { 297 whandle->handle = mt->bo->handle; 298 return TRUE; 299 } else { 300 return FALSE; 301 } 302} 303 304int 305nouveau_screen_init(struct nouveau_screen *screen, struct nouveau_device *dev) 306{ 307 struct pipe_screen *pscreen = &screen->base; 308 int ret; 309 310 ret = nouveau_channel_alloc(dev, 0xbeef0201, 0xbeef0202, 311 &screen->channel); 312 if (ret) 313 return ret; 314 screen->device = dev; 315 316 pscreen->get_name = nouveau_screen_get_name; 317 pscreen->get_vendor = nouveau_screen_get_vendor; 318 319 pscreen->buffer_create = nouveau_screen_bo_new; 320 pscreen->user_buffer_create = nouveau_screen_bo_user; 321 pscreen->buffer_map = nouveau_screen_bo_map; 322 pscreen->buffer_map_range = nouveau_screen_bo_map_range; 323 pscreen->buffer_flush_mapped_range = nouveau_screen_bo_map_flush; 324 pscreen->buffer_unmap = nouveau_screen_bo_unmap; 325 pscreen->buffer_destroy = nouveau_screen_bo_del; 326 327 pscreen->fence_reference = nouveau_screen_fence_ref; 328 pscreen->fence_signalled = nouveau_screen_fence_signalled; 329 pscreen->fence_finish = nouveau_screen_fence_finish; 330 331 pscreen->texture_from_handle = nouveau_screen_texture_from_handle; 332 pscreen->texture_get_handle = nouveau_screen_texture_get_handle; 333 334 return 0; 335} 336 337void 338nouveau_screen_fini(struct nouveau_screen *screen) 339{ 340 struct pipe_winsys *ws = screen->base.winsys; 341 nouveau_channel_free(&screen->channel); 342 ws->destroy(ws); 343} 344 345