#include "pipe/p_defines.h" #include "pipe/p_screen.h" #include "pipe/p_state.h" #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 #include #include "nouveau/nouveau_bo.h" #include "nouveau_winsys.h" #include "nouveau_screen.h" #include "nouveau_fence.h" /* XXX this should go away */ #include "state_tracker/drm_driver.h" #include "util/u_simple_screen.h" static const char * nouveau_screen_get_name(struct pipe_screen *pscreen) { struct nouveau_device *dev = nouveau_screen(pscreen)->device; static char buffer[128]; util_snprintf(buffer, sizeof(buffer), "NV%02X", dev->chipset); return buffer; } static const char * nouveau_screen_get_vendor(struct pipe_screen *pscreen) { return "nouveau"; } struct nouveau_bo * nouveau_screen_bo_new(struct pipe_screen *pscreen, unsigned alignment, unsigned usage, unsigned bind, unsigned size) { 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 (bind & PIPE_BIND_VERTEX_BUFFER) flags |= nouveau_screen(pscreen)->vertex_buffer_flags; else if (bind & PIPE_BIND_INDEX_BUFFER) flags |= nouveau_screen(pscreen)->index_buffer_flags; if (bind & (PIPE_BIND_RENDER_TARGET | PIPE_BIND_DEPTH_STENCIL | PIPE_BIND_SCANOUT | PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_SAMPLER_VIEW)) { /* TODO: this may be incorrect or suboptimal */ if (!(bind & PIPE_BIND_SCANOUT)) flags |= NOUVEAU_BO_GART; if (usage != PIPE_USAGE_DYNAMIC) flags |= NOUVEAU_BO_VRAM; if (dev->chipset == 0x50 || dev->chipset >= 0x80) { if (bind & PIPE_BIND_DEPTH_STENCIL) 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 bo; } struct nouveau_bo * nouveau_screen_bo_user(struct pipe_screen *pscreen, void *ptr, unsigned bytes) { struct nouveau_device *dev = nouveau_screen(pscreen)->device; struct nouveau_bo *bo = NULL; int ret; ret = nouveau_bo_user(dev, ptr, bytes, &bo); if (ret) return NULL; return bo; } void * nouveau_screen_bo_map(struct pipe_screen *pscreen, struct nouveau_bo *bo, unsigned map_flags) { int ret; ret = nouveau_bo_map(bo, map_flags); if (ret) { debug_printf("map failed: %d\n", ret); return NULL; } return bo->map; } void * nouveau_screen_bo_map_range(struct pipe_screen *pscreen, struct nouveau_bo *bo, unsigned offset, unsigned length, unsigned flags) { int ret; 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? */ } void nouveau_screen_bo_map_flush_range(struct pipe_screen *pscreen, struct nouveau_bo *bo, unsigned offset, unsigned length) { nouveau_bo_map_flush(bo, offset, length); } void nouveau_screen_bo_unmap(struct pipe_screen *pscreen, struct nouveau_bo *bo) { nouveau_bo_unmap(bo); } void nouveau_screen_bo_release(struct pipe_screen *pscreen, struct nouveau_bo *bo) { nouveau_bo_ref(NULL, &bo); } static void nouveau_screen_fence_ref(struct pipe_screen *pscreen, struct pipe_fence_handle **ptr, struct pipe_fence_handle *pfence) { nouveau_fence_ref(nouveau_fence(pfence), (struct nouveau_fence **)ptr); } static int nouveau_screen_fence_signalled(struct pipe_screen *screen, struct pipe_fence_handle *pfence, unsigned flags) { return !nouveau_fence_signalled(nouveau_fence(pfence)); } static int nouveau_screen_fence_finish(struct pipe_screen *screen, struct pipe_fence_handle *pfence, unsigned flags, uint64_t timeout) { return !nouveau_fence_wait(nouveau_fence(pfence)); } 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; ret = nouveau_bo_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; } boolean 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_handle_get(bo, &whandle->handle) == 0; } else if (whandle->type == DRM_API_HANDLE_TYPE_KMS) { whandle->handle = bo->handle; return TRUE; } else { return FALSE; } } unsigned int nouveau_reference_flags(struct nouveau_bo *bo) { uint32_t bo_flags; int flags = 0; bo_flags = nouveau_bo_pending(bo); if (bo_flags & NOUVEAU_BO_RD) flags |= PIPE_REFERENCED_FOR_READ; if (bo_flags & NOUVEAU_BO_WR) flags |= PIPE_REFERENCED_FOR_WRITE; return flags; } int nouveau_screen_init(struct nouveau_screen *screen, struct nouveau_device *dev) { struct pipe_screen *pscreen = &screen->base; int ret; ret = nouveau_channel_alloc(dev, 0xbeef0201, 0xbeef0202, 512*1024, &screen->channel); if (ret) return ret; screen->device = dev; pscreen->get_name = nouveau_screen_get_name; pscreen->get_vendor = nouveau_screen_get_vendor; pscreen->fence_reference = nouveau_screen_fence_ref; pscreen->fence_signalled = nouveau_screen_fence_signalled; pscreen->fence_finish = nouveau_screen_fence_finish; util_format_s3tc_init(); screen->mm_GART = nouveau_mm_create(dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0x000); screen->mm_VRAM = nouveau_mm_create(dev, NOUVEAU_BO_VRAM, 0x000); return 0; } void nouveau_screen_fini(struct nouveau_screen *screen) { struct pipe_winsys *ws = screen->base.winsys; nouveau_mm_destroy(screen->mm_GART); nouveau_mm_destroy(screen->mm_VRAM); nouveau_channel_free(&screen->channel); if (ws) ws->destroy(ws); }