diff options
Diffstat (limited to 'src/gallium/winsys/nouveau')
-rw-r--r-- | src/gallium/winsys/nouveau/drm/Makefile | 11 | ||||
-rw-r--r-- | src/gallium/winsys/nouveau/drm/nouveau_dri.h | 28 | ||||
-rw-r--r-- | src/gallium/winsys/nouveau/drm/nouveau_drm_api.c | 160 | ||||
-rw-r--r-- | src/gallium/winsys/nouveau/drm/nouveau_drm_api.h | 31 |
4 files changed, 230 insertions, 0 deletions
diff --git a/src/gallium/winsys/nouveau/drm/Makefile b/src/gallium/winsys/nouveau/drm/Makefile new file mode 100644 index 00000000000..71029858f75 --- /dev/null +++ b/src/gallium/winsys/nouveau/drm/Makefile @@ -0,0 +1,11 @@ +TOP = ../../../../.. +include $(TOP)/configs/current + +LIBNAME = nouveaudrm + +C_SOURCES = nouveau_drm_api.c + +LIBRARY_INCLUDES = $(shell pkg-config libdrm libdrm_nouveau --cflags-only-I) +LIBRARY_DEFINES = $(shell pkg-config libdrm libdrm_nouveau --cflags-only-other) + +include ../../../Makefile.template diff --git a/src/gallium/winsys/nouveau/drm/nouveau_dri.h b/src/gallium/winsys/nouveau/drm/nouveau_dri.h new file mode 100644 index 00000000000..1207c2d609c --- /dev/null +++ b/src/gallium/winsys/nouveau/drm/nouveau_dri.h @@ -0,0 +1,28 @@ +#ifndef _NOUVEAU_DRI_ +#define _NOUVEAU_DRI_ + +#include "xf86drm.h" +#include "drm.h" +#include "nouveau_drm.h" + +struct nouveau_dri { + uint32_t device_id; /**< \brief PCI device ID */ + uint32_t width; /**< \brief width in pixels of display */ + uint32_t height; /**< \brief height in scanlines of display */ + uint32_t depth; /**< \brief depth of display (8, 15, 16, 24) */ + uint32_t bpp; /**< \brief bit depth of display (8, 16, 24, 32) */ + + uint32_t bus_type; /**< \brief ths bus type */ + uint32_t bus_mode; /**< \brief bus mode (used for AGP, maybe also for PCI-E ?) */ + + uint32_t front_offset; /**< \brief front buffer offset */ + uint32_t front_pitch; /**< \brief front buffer pitch */ + uint32_t back_offset; /**< \brief private back buffer offset */ + uint32_t back_pitch; /**< \brief private back buffer pitch */ + uint32_t depth_offset; /**< \brief private depth buffer offset */ + uint32_t depth_pitch; /**< \brief private depth buffer pitch */ + +}; + +#endif + diff --git a/src/gallium/winsys/nouveau/drm/nouveau_drm_api.c b/src/gallium/winsys/nouveau/drm/nouveau_drm_api.c new file mode 100644 index 00000000000..37f33875a5b --- /dev/null +++ b/src/gallium/winsys/nouveau/drm/nouveau_drm_api.c @@ -0,0 +1,160 @@ +#include "pipe/p_context.h" +#include "pipe/p_state.h" +#include "util/u_format.h" +#include "util/u_memory.h" +#include "util/u_inlines.h" + +#include "nouveau_drm_api.h" + +#include "nouveau_drmif.h" +#include "nouveau_channel.h" +#include "nouveau_bo.h" + +#include "nouveau/nouveau_winsys.h" +#include "nouveau/nouveau_screen.h" + +static struct pipe_surface * +dri_surface_from_handle(struct drm_api *api, struct pipe_screen *pscreen, + unsigned handle, enum pipe_format format, + unsigned width, unsigned height, unsigned pitch) +{ + struct pipe_surface *ps = NULL; + struct pipe_resource *pt = NULL; + struct pipe_resource tmpl; + struct winsys_handle whandle; + unsigned bind = (PIPE_BIND_SCANOUT | + PIPE_BIND_RENDER_TARGET | + PIPE_BIND_BLIT_DESTINATION | + PIPE_BIND_BLIT_SOURCE); + + memset(&tmpl, 0, sizeof(tmpl)); + tmpl.bind = bind; + tmpl.target = PIPE_TEXTURE_2D; + tmpl.last_level = 0; + tmpl.depth0 = 1; + tmpl.format = format; + tmpl.width0 = width; + tmpl.height0 = height; + + memset(&whandle, 0, sizeof(whandle)); + whandle.stride = pitch; + whandle.handle = handle; + + pt = pscreen->resource_from_handle(pscreen, &tmpl, &whandle); + if (!pt) + return NULL; + + ps = pscreen->get_tex_surface(pscreen, pt, 0, 0, 0, bind); + + /* we don't need the texture from this point on */ + pipe_resource_reference(&pt, NULL); + return ps; +} + +static struct pipe_surface * +nouveau_dri1_front_surface(struct pipe_screen *screen) +{ + return nouveau_winsys_screen(screen)->front; +} + +static struct dri1_api nouveau_dri1_api = { + nouveau_dri1_front_surface, +}; + +static void +nouveau_drm_destroy_winsys(struct pipe_winsys *s) +{ + struct nouveau_winsys *nv_winsys = nouveau_winsys(s); + struct nouveau_screen *nv_screen= nouveau_screen(nv_winsys->pscreen); + nouveau_device_close(&nv_screen->device); + FREE(nv_winsys); +} + +static struct pipe_screen * +nouveau_drm_create_screen(struct drm_api *api, int fd, + struct drm_create_screen_arg *arg) +{ + struct dri1_create_screen_arg *dri1 = (void *)arg; + struct nouveau_winsys *nvws; + struct pipe_winsys *ws; + struct nouveau_device *dev = NULL; + struct pipe_screen *(*init)(struct pipe_winsys *, + struct nouveau_device *); + int ret; + + ret = nouveau_device_open_existing(&dev, 0, fd, 0); + if (ret) + return NULL; + + switch (dev->chipset & 0xf0) { + case 0x30: + case 0x40: + case 0x60: + init = nvfx_screen_create; + break; + case 0x50: + case 0x80: + case 0x90: + case 0xa0: + init = nv50_screen_create; + break; + default: + debug_printf("%s: unknown chipset nv%02x\n", __func__, + dev->chipset); + return NULL; + } + + nvws = CALLOC_STRUCT(nouveau_winsys); + if (!nvws) { + nouveau_device_close(&dev); + return NULL; + } + ws = &nvws->base; + ws->destroy = nouveau_drm_destroy_winsys; + + nvws->pscreen = init(ws, dev); + if (!nvws->pscreen) { + ws->destroy(ws); + return NULL; + } + + if (arg && arg->mode == DRM_CREATE_DRI1) { + struct nouveau_dri *nvdri = dri1->ddx_info; + enum pipe_format format; + + if (nvdri->bpp == 16) + format = PIPE_FORMAT_B5G6R5_UNORM; + else + format = PIPE_FORMAT_B8G8R8A8_UNORM; + + nvws->front = dri_surface_from_handle(api, nvws->pscreen, + nvdri->front_offset, + format, nvdri->width, + nvdri->height, + nvdri->front_pitch * + (nvdri->bpp / 8)); + if (!nvws->front) { + debug_printf("%s: error referencing front buffer\n", + __func__); + ws->destroy(ws); + return NULL; + } + + dri1->api = &nouveau_dri1_api; + } + + return nvws->pscreen; +} + +static struct drm_api nouveau_drm_api_hooks = { + .name = "nouveau", + .driver_name = "nouveau", + .create_screen = nouveau_drm_create_screen, + .destroy = NULL, +}; + +struct drm_api * +drm_api_create() { + return &nouveau_drm_api_hooks; +} + diff --git a/src/gallium/winsys/nouveau/drm/nouveau_drm_api.h b/src/gallium/winsys/nouveau/drm/nouveau_drm_api.h new file mode 100644 index 00000000000..a91aad7df8e --- /dev/null +++ b/src/gallium/winsys/nouveau/drm/nouveau_drm_api.h @@ -0,0 +1,31 @@ +#ifndef __NOUVEAU_DRM_API_H__ +#define __NOUVEAU_DRM_API_H__ + +#include "state_tracker/drm_api.h" +#include "state_tracker/dri1_api.h" + +#include "util/u_simple_screen.h" + +#include "nouveau_dri.h" + +struct nouveau_winsys { + struct pipe_winsys base; + + struct pipe_screen *pscreen; + + struct pipe_surface *front; +}; + +static INLINE struct nouveau_winsys * +nouveau_winsys(struct pipe_winsys *ws) +{ + return (struct nouveau_winsys *)ws; +} + +static INLINE struct nouveau_winsys * +nouveau_winsys_screen(struct pipe_screen *pscreen) +{ + return nouveau_winsys(pscreen->winsys); +} + +#endif |