X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fdrivers%2Fnouveau%2Fnouveau_screen.c;h=c144b39b2dd2d1ade24424182cbd19351a7ce7f8;hb=222a2fb99859f3ac237def59d40413bb1a464f11;hp=b1ad686022a0905f838cca62dfb3804f3e2046c8;hpb=feb619b7705897ca723e8fe728f739932f743327;p=mesa.git diff --git a/src/gallium/drivers/nouveau/nouveau_screen.c b/src/gallium/drivers/nouveau/nouveau_screen.c index b1ad686022a..c144b39b2dd 100644 --- a/src/gallium/drivers/nouveau/nouveau_screen.c +++ b/src/gallium/drivers/nouveau/nouveau_screen.c @@ -5,340 +5,299 @@ #include "util/u_memory.h" #include "util/u_inlines.h" #include "util/u_format.h" +#include "util/u_format_s3tc.h" +#include "util/u_string.h" + +#include "util/os_time.h" #include #include +#include + +#include -#include "nouveau/nouveau_bo.h" #include "nouveau_winsys.h" #include "nouveau_screen.h" +#include "nouveau_context.h" +#include "nouveau_fence.h" +#include "nouveau_mm.h" +#include "nouveau_buffer.h" /* XXX this should go away */ -#include "state_tracker/drm_api.h" +#include "state_tracker/drm_driver.h" + +int nouveau_mesa_debug = 0; static const char * nouveau_screen_get_name(struct pipe_screen *pscreen) { - struct nouveau_device *dev = nouveau_screen(pscreen)->device; - static char buffer[128]; + struct nouveau_device *dev = nouveau_screen(pscreen)->device; + static char buffer[128]; - snprintf(buffer, sizeof(buffer), "NV%02X", dev->chipset); - return buffer; + util_snprintf(buffer, sizeof(buffer), "NV%02X", dev->chipset); + return buffer; } static const char * nouveau_screen_get_vendor(struct pipe_screen *pscreen) { - return "nouveau"; -} - -static struct pipe_buffer * -nouveau_screen_bo_skel(struct pipe_screen *pscreen, struct nouveau_bo *bo, - unsigned alignment, unsigned usage, unsigned size) -{ - struct pipe_buffer *pb; - - pb = CALLOC(1, sizeof(struct pipe_buffer)+sizeof(struct nouveau_bo *)); - if (!pb) { - nouveau_bo_ref(NULL, &bo); - return NULL; - } - - pipe_reference_init(&pb->reference, 1); - pb->screen = pscreen; - pb->alignment = alignment; - pb->usage = usage; - pb->size = size; - *(struct nouveau_bo **)(pb + 1) = bo; - return pb; + return "nouveau"; } -static struct pipe_buffer * -nouveau_screen_bo_new(struct pipe_screen *pscreen, unsigned alignment, - unsigned usage, unsigned size) +static const char * +nouveau_screen_get_device_vendor(struct pipe_screen *pscreen) { - struct nouveau_device *dev = nouveau_screen(pscreen)->device; - struct nouveau_bo *bo = NULL; - uint32_t flags = NOUVEAU_BO_MAP, tile_mode = 0, tile_flags = 0; - int ret; - - if (usage & NOUVEAU_BUFFER_USAGE_TRANSFER) - flags |= NOUVEAU_BO_GART; - else - if (usage & PIPE_BUFFER_USAGE_VERTEX) { - if (pscreen->get_param(pscreen, NOUVEAU_CAP_HW_VTXBUF)) - flags |= NOUVEAU_BO_GART; - } else - if (usage & PIPE_BUFFER_USAGE_INDEX) { - if (pscreen->get_param(pscreen, NOUVEAU_CAP_HW_IDXBUF)) - flags |= NOUVEAU_BO_GART; - } - - if (usage & PIPE_BUFFER_USAGE_PIXEL) { - if (usage & NOUVEAU_BUFFER_USAGE_TEXTURE) - flags |= NOUVEAU_BO_GART; - if (!(usage & PIPE_BUFFER_USAGE_CPU_READ_WRITE)) - flags |= NOUVEAU_BO_VRAM; - - if (dev->chipset == 0x50 || dev->chipset >= 0x80) { - if (usage & NOUVEAU_BUFFER_USAGE_ZETA) - tile_flags = 0x2800; - else - tile_flags = 0x7000; - } - } - - ret = nouveau_bo_new_tile(dev, flags, alignment, size, - tile_mode, tile_flags, &bo); - if (ret) - return NULL; - - return nouveau_screen_bo_skel(pscreen, bo, alignment, usage, size); + return "NVIDIA"; } -static struct pipe_buffer * -nouveau_screen_bo_user(struct pipe_screen *pscreen, void *ptr, unsigned bytes) +static uint64_t +nouveau_screen_get_timestamp(struct pipe_screen *pscreen) { - struct nouveau_device *dev = nouveau_screen(pscreen)->device; - struct nouveau_bo *bo = NULL; - int ret; + int64_t cpu_time = os_time_get() * 1000; - ret = nouveau_bo_user(dev, ptr, bytes, &bo); - if (ret) - return NULL; + /* getparam of PTIMER_TIME takes about x10 as long (several usecs) */ - return nouveau_screen_bo_skel(pscreen, bo, 0, 0, bytes); -} - -static inline uint32_t -nouveau_screen_map_flags(unsigned pipe) -{ - uint32_t flags = 0; - - if (pipe & PIPE_BUFFER_USAGE_CPU_READ) - flags |= NOUVEAU_BO_RD; - if (pipe & PIPE_BUFFER_USAGE_CPU_WRITE) - flags |= NOUVEAU_BO_WR; - if (pipe & PIPE_BUFFER_USAGE_DISCARD) - flags |= NOUVEAU_BO_INVAL; - if (pipe & PIPE_BUFFER_USAGE_DONTBLOCK) - flags |= NOUVEAU_BO_NOWAIT; - else - if (pipe & PIPE_BUFFER_USAGE_UNSYNCHRONIZED) - flags |= NOUVEAU_BO_NOSYNC; - - return flags; + return cpu_time + nouveau_screen(pscreen)->cpu_gpu_time_delta; } -static void * -nouveau_screen_bo_map(struct pipe_screen *pscreen, struct pipe_buffer *pb, - unsigned usage) +static struct disk_cache * +nouveau_screen_get_disk_shader_cache(struct pipe_screen *pscreen) { - struct nouveau_bo *bo = nouveau_bo(pb); - struct nouveau_screen *nscreen = nouveau_screen(pscreen); - int ret; - - if (nscreen->pre_pipebuffer_map_callback) { - ret = nscreen->pre_pipebuffer_map_callback(pscreen, pb, usage); - if (ret) { - debug_printf("pre_pipebuffer_map_callback failed %d\n", - ret); - return NULL; - } - } - - ret = nouveau_bo_map(bo, nouveau_screen_map_flags(usage)); - if (ret) { - debug_printf("map failed: %d\n", ret); - return NULL; - } - - return bo->map; + return nouveau_screen(pscreen)->disk_shader_cache; } -static void * -nouveau_screen_bo_map_range(struct pipe_screen *pscreen, struct pipe_buffer *pb, - unsigned offset, unsigned length, unsigned usage) +static void +nouveau_screen_fence_ref(struct pipe_screen *pscreen, + struct pipe_fence_handle **ptr, + struct pipe_fence_handle *pfence) { - struct nouveau_bo *bo = nouveau_bo(pb); - struct nouveau_screen *nscreen = nouveau_screen(pscreen); - uint32_t flags = nouveau_screen_map_flags(usage); - int ret; - - if (nscreen->pre_pipebuffer_map_callback) { - ret = nscreen->pre_pipebuffer_map_callback(pscreen, pb, usage); - if (ret) { - debug_printf("pre_pipebuffer_map_callback failed %d\n", - ret); - return NULL; - } - } - - ret = nouveau_bo_map_range(bo, offset, length, flags); - if (ret) { - nouveau_bo_unmap(bo); - if (!(flags & NOUVEAU_BO_NOWAIT) || ret != -EBUSY) - debug_printf("map_range failed: %d\n", ret); - return NULL; - } - - return (char *)bo->map - offset; /* why gallium? why? */ + nouveau_fence_ref(nouveau_fence(pfence), (struct nouveau_fence **)ptr); } -static void -nouveau_screen_bo_map_flush(struct pipe_screen *pscreen, struct pipe_buffer *pb, - unsigned offset, unsigned length) +static boolean +nouveau_screen_fence_finish(struct pipe_screen *screen, + struct pipe_context *ctx, + struct pipe_fence_handle *pfence, + uint64_t timeout) { - struct nouveau_bo *bo = nouveau_bo(pb); + if (!timeout) + return nouveau_fence_signalled(nouveau_fence(pfence)); - nouveau_bo_map_flush(bo, offset, length); + return nouveau_fence_wait(nouveau_fence(pfence), NULL); } -static void -nouveau_screen_bo_unmap(struct pipe_screen *pscreen, struct pipe_buffer *pb) -{ - struct nouveau_bo *bo = nouveau_bo(pb); - nouveau_bo_unmap(bo); +struct nouveau_bo * +nouveau_screen_bo_from_handle(struct pipe_screen *pscreen, + struct winsys_handle *whandle, + unsigned *out_stride) +{ + struct nouveau_device *dev = nouveau_screen(pscreen)->device; + struct nouveau_bo *bo = 0; + int ret; + + if (whandle->offset != 0) { + debug_printf("%s: attempt to import unsupported winsys offset %d\n", + __FUNCTION__, whandle->offset); + return NULL; + } + + if (whandle->type != DRM_API_HANDLE_TYPE_SHARED && + whandle->type != DRM_API_HANDLE_TYPE_FD) { + debug_printf("%s: attempt to import unsupported handle type %d\n", + __FUNCTION__, whandle->type); + return NULL; + } + + if (whandle->type == DRM_API_HANDLE_TYPE_SHARED) + ret = nouveau_bo_name_ref(dev, whandle->handle, &bo); + else + ret = nouveau_bo_prime_handle_ref(dev, whandle->handle, &bo); + + if (ret) { + debug_printf("%s: ref name 0x%08x failed with %d\n", + __FUNCTION__, whandle->handle, ret); + return NULL; + } + + *out_stride = whandle->stride; + return bo; } -static void -nouveau_screen_bo_del(struct pipe_buffer *pb) -{ - struct nouveau_bo *bo = nouveau_bo(pb); - nouveau_bo_ref(NULL, &bo); - FREE(pb); +bool +nouveau_screen_bo_get_handle(struct pipe_screen *pscreen, + struct nouveau_bo *bo, + unsigned stride, + struct winsys_handle *whandle) +{ + whandle->stride = stride; + + if (whandle->type == DRM_API_HANDLE_TYPE_SHARED) { + return nouveau_bo_name_get(bo, &whandle->handle) == 0; + } else if (whandle->type == DRM_API_HANDLE_TYPE_KMS) { + whandle->handle = bo->handle; + return true; + } else if (whandle->type == DRM_API_HANDLE_TYPE_FD) { + return nouveau_bo_set_prime(bo, (int *)&whandle->handle) == 0; + } else { + return false; + } } static void -nouveau_screen_fence_ref(struct pipe_screen *pscreen, - struct pipe_fence_handle **ptr, - struct pipe_fence_handle *pfence) +nouveau_disk_cache_create(struct nouveau_screen *screen) { - *ptr = pfence; + uint32_t mesa_timestamp; + char *timestamp_str; + int res; + + if (disk_cache_get_function_timestamp(nouveau_disk_cache_create, + &mesa_timestamp)) { + res = asprintf(×tamp_str, "%u", mesa_timestamp); + if (res != -1) { + screen->disk_shader_cache = + disk_cache_create(nouveau_screen_get_name(&screen->base), + timestamp_str, 0); + free(timestamp_str); + } + } } -static int -nouveau_screen_fence_signalled(struct pipe_screen *screen, - struct pipe_fence_handle *pfence, - unsigned flags) +int +nouveau_screen_init(struct nouveau_screen *screen, struct nouveau_device *dev) { - return 0; + struct pipe_screen *pscreen = &screen->base; + struct nv04_fifo nv04_data = { .vram = 0xbeef0201, .gart = 0xbeef0202 }; + struct nvc0_fifo nvc0_data = { }; + uint64_t time; + int size, ret; + void *data; + union nouveau_bo_config mm_config; + + char *nv_dbg = getenv("NOUVEAU_MESA_DEBUG"); + if (nv_dbg) + nouveau_mesa_debug = atoi(nv_dbg); + + /* These must be set before any failure is possible, as the cleanup + * paths assume they're responsible for deleting them. + */ + screen->drm = nouveau_drm(&dev->object); + screen->device = dev; + + /* + * this is initialized to 1 in nouveau_drm_screen_create after screen + * is fully constructed and added to the global screen list. + */ + screen->refcount = -1; + + if (dev->chipset < 0xc0) { + data = &nv04_data; + size = sizeof(nv04_data); + } else { + data = &nvc0_data; + size = sizeof(nvc0_data); + } + + /* + * Set default VRAM domain if not overridden + */ + if (!screen->vram_domain) { + if (dev->vram_size > 0) + screen->vram_domain = NOUVEAU_BO_VRAM; + else + screen->vram_domain = NOUVEAU_BO_GART; + } + + ret = nouveau_object_new(&dev->object, 0, NOUVEAU_FIFO_CHANNEL_CLASS, + data, size, &screen->channel); + if (ret) + return ret; + + ret = nouveau_client_new(screen->device, &screen->client); + if (ret) + return ret; + ret = nouveau_pushbuf_new(screen->client, screen->channel, + 4, 512 * 1024, 1, + &screen->pushbuf); + if (ret) + return ret; + + /* getting CPU time first appears to be more accurate */ + screen->cpu_gpu_time_delta = os_time_get(); + + ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_PTIMER_TIME, &time); + if (!ret) + screen->cpu_gpu_time_delta = time - screen->cpu_gpu_time_delta * 1000; + + pscreen->get_name = nouveau_screen_get_name; + pscreen->get_vendor = nouveau_screen_get_vendor; + pscreen->get_device_vendor = nouveau_screen_get_device_vendor; + pscreen->get_disk_shader_cache = nouveau_screen_get_disk_shader_cache; + + pscreen->get_timestamp = nouveau_screen_get_timestamp; + + pscreen->fence_reference = nouveau_screen_fence_ref; + pscreen->fence_finish = nouveau_screen_fence_finish; + + nouveau_disk_cache_create(screen); + + screen->lowmem_bindings = PIPE_BIND_GLOBAL; /* gallium limit */ + screen->vidmem_bindings = + PIPE_BIND_RENDER_TARGET | PIPE_BIND_DEPTH_STENCIL | + PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_SCANOUT | + PIPE_BIND_CURSOR | + PIPE_BIND_SAMPLER_VIEW | + PIPE_BIND_SHADER_BUFFER | PIPE_BIND_SHADER_IMAGE | + PIPE_BIND_COMPUTE_RESOURCE | + PIPE_BIND_GLOBAL; + screen->sysmem_bindings = + PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_STREAM_OUTPUT | + PIPE_BIND_COMMAND_ARGS_BUFFER; + + memset(&mm_config, 0, sizeof(mm_config)); + + screen->mm_GART = nouveau_mm_create(dev, + NOUVEAU_BO_GART | NOUVEAU_BO_MAP, + &mm_config); + screen->mm_VRAM = nouveau_mm_create(dev, NOUVEAU_BO_VRAM, &mm_config); + return 0; } -static int -nouveau_screen_fence_finish(struct pipe_screen *screen, - struct pipe_fence_handle *pfence, - unsigned flags) +void +nouveau_screen_fini(struct nouveau_screen *screen) { - return 0; -} + int fd = screen->drm->fd; + nouveau_mm_destroy(screen->mm_GART); + nouveau_mm_destroy(screen->mm_VRAM); -/* - * Both texture_{from|get}_handle use drm api defines directly which they - * shouldn't do. The problem is that from|get are pipe functions and as - * such they should be defined in the pipe level. If nouveau had a propper - * winsys interface we would have added from|get to that interface using - * the winsys_handle struct as done with other drivers. However this code - * calls directly into the libdrm_nouveau.so functions (nouveau_bo_*). So - * we need to translate the handle into something they understand. - */ -static struct pipe_texture * -nouveau_screen_texture_from_handle(struct pipe_screen *pscreen, - const struct pipe_texture *templ, - struct winsys_handle *whandle) -{ - struct nouveau_device *dev = nouveau_screen(pscreen)->device; - struct pipe_texture *pt; - struct pipe_buffer *pb; - int ret; - - pb = CALLOC(1, sizeof(struct pipe_buffer) + sizeof(struct nouveau_bo*)); - if (!pb) - return NULL; - - ret = nouveau_bo_handle_ref(dev, whandle->handle, (struct nouveau_bo**)(pb+1)); - if (ret) { - debug_printf("%s: ref name 0x%08x failed with %d\n", - __func__, whandle->handle, ret); - FREE(pb); - return NULL; - } - - pipe_reference_init(&pb->reference, 1); - pb->screen = pscreen; - pb->alignment = 0; - pb->usage = PIPE_BUFFER_USAGE_GPU_READ_WRITE | - PIPE_BUFFER_USAGE_CPU_READ_WRITE; - pb->size = nouveau_bo(pb)->size; - pt = nouveau_screen(pscreen)->texture_blanket(pscreen, templ, - &whandle->stride, pb); - pipe_buffer_reference(&pb, NULL); - return pt; -} + nouveau_pushbuf_del(&screen->pushbuf); -static boolean -nouveau_screen_texture_get_handle(struct pipe_screen *pscreen, - struct pipe_texture *pt, - struct winsys_handle *whandle) -{ - struct nouveau_miptree *mt = nouveau_miptree(pt); - - if (!mt || !mt->bo) - return false; + nouveau_client_del(&screen->client); + nouveau_object_del(&screen->channel); - whandle->stride = util_format_get_stride(mt->base.format, mt->base.width0); + nouveau_device_del(&screen->device); + nouveau_drm_del(&screen->drm); + close(fd); - if (whandle->type == DRM_API_HANDLE_TYPE_SHARED) { - return nouveau_bo_handle_get(mt->bo, &whandle->handle) == 0; - } else if (whandle->type == DRM_API_HANDLE_TYPE_KMS) { - whandle->handle = mt->bo->handle; - return TRUE; - } else { - return FALSE; - } + disk_cache_destroy(screen->disk_shader_cache); } -int -nouveau_screen_init(struct nouveau_screen *screen, struct nouveau_device *dev) +static void +nouveau_set_debug_callback(struct pipe_context *pipe, + const struct pipe_debug_callback *cb) { - struct pipe_screen *pscreen = &screen->base; - int ret; - - ret = nouveau_channel_alloc(dev, 0xbeef0201, 0xbeef0202, - &screen->channel); - if (ret) - return ret; - screen->device = dev; - - pscreen->get_name = nouveau_screen_get_name; - pscreen->get_vendor = nouveau_screen_get_vendor; - - pscreen->buffer_create = nouveau_screen_bo_new; - pscreen->user_buffer_create = nouveau_screen_bo_user; - pscreen->buffer_map = nouveau_screen_bo_map; - pscreen->buffer_map_range = nouveau_screen_bo_map_range; - pscreen->buffer_flush_mapped_range = nouveau_screen_bo_map_flush; - pscreen->buffer_unmap = nouveau_screen_bo_unmap; - pscreen->buffer_destroy = nouveau_screen_bo_del; - - pscreen->fence_reference = nouveau_screen_fence_ref; - pscreen->fence_signalled = nouveau_screen_fence_signalled; - pscreen->fence_finish = nouveau_screen_fence_finish; - - pscreen->texture_from_handle = nouveau_screen_texture_from_handle; - pscreen->texture_get_handle = nouveau_screen_texture_get_handle; - - return 0; + struct nouveau_context *context = nouveau_context(pipe); + + if (cb) + context->debug = *cb; + else + memset(&context->debug, 0, sizeof(context->debug)); } void -nouveau_screen_fini(struct nouveau_screen *screen) +nouveau_context_init(struct nouveau_context *context) { - struct pipe_winsys *ws = screen->base.winsys; - nouveau_channel_free(&screen->channel); - ws->destroy(ws); + context->pipe.set_debug_callback = nouveau_set_debug_callback; } -