Merge branch '7.8'
[mesa.git] / src / gallium / winsys / drm / nouveau / drm / nouveau_drm_api.c
1 #include "pipe/p_context.h"
2 #include "pipe/p_state.h"
3 #include "util/u_format.h"
4 #include "util/u_memory.h"
5 #include "util/u_inlines.h"
6
7 #include "nouveau_drm_api.h"
8
9 #include "nouveau_drmif.h"
10 #include "nouveau_channel.h"
11 #include "nouveau_bo.h"
12
13 #include "nouveau/nouveau_winsys.h"
14 #include "nouveau/nouveau_screen.h"
15
16 static struct pipe_surface *
17 dri_surface_from_handle(struct drm_api *api, struct pipe_screen *pscreen,
18 unsigned handle, enum pipe_format format,
19 unsigned width, unsigned height, unsigned pitch)
20 {
21 struct pipe_surface *ps = NULL;
22 struct pipe_texture *pt = NULL;
23 struct pipe_texture tmpl;
24 struct winsys_handle whandle;
25
26 memset(&tmpl, 0, sizeof(tmpl));
27 tmpl.tex_usage = PIPE_TEXTURE_USAGE_SCANOUT;
28 tmpl.target = PIPE_TEXTURE_2D;
29 tmpl.last_level = 0;
30 tmpl.depth0 = 1;
31 tmpl.format = format;
32 tmpl.width0 = width;
33 tmpl.height0 = height;
34
35 memset(&whandle, 0, sizeof(whandle));
36 whandle.stride = pitch;
37 whandle.handle = handle;
38
39 pt = pscreen->texture_from_handle(pscreen, &tmpl, &whandle);
40 if (!pt)
41 return NULL;
42
43 ps = pscreen->get_tex_surface(pscreen, pt, 0, 0, 0,
44 PIPE_BUFFER_USAGE_GPU_READ |
45 PIPE_BUFFER_USAGE_GPU_WRITE);
46
47 /* we don't need the texture from this point on */
48 pipe_texture_reference(&pt, NULL);
49 return ps;
50 }
51
52 static struct pipe_surface *
53 nouveau_dri1_front_surface(struct pipe_context *pipe)
54 {
55 return nouveau_winsys_screen(pipe->screen)->front;
56 }
57
58 static struct dri1_api nouveau_dri1_api = {
59 nouveau_dri1_front_surface,
60 };
61
62 static void
63 nouveau_drm_destroy_winsys(struct pipe_winsys *s)
64 {
65 struct nouveau_winsys *nv_winsys = nouveau_winsys(s);
66 struct nouveau_screen *nv_screen= nouveau_screen(nv_winsys->pscreen);
67 nouveau_device_close(&nv_screen->device);
68 FREE(nv_winsys);
69 }
70
71 static struct pipe_screen *
72 nouveau_drm_create_screen(struct drm_api *api, int fd,
73 struct drm_create_screen_arg *arg)
74 {
75 struct dri1_create_screen_arg *dri1 = (void *)arg;
76 struct nouveau_winsys *nvws;
77 struct pipe_winsys *ws;
78 struct nouveau_device *dev = NULL;
79 struct pipe_screen *(*init)(struct pipe_winsys *,
80 struct nouveau_device *);
81 int ret;
82
83 ret = nouveau_device_open_existing(&dev, 0, fd, 0);
84 if (ret)
85 return NULL;
86
87 switch (dev->chipset & 0xf0) {
88 case 0x30:
89 case 0x40:
90 case 0x60:
91 init = nvfx_screen_create;
92 break;
93 case 0x50:
94 case 0x80:
95 case 0x90:
96 case 0xa0:
97 init = nv50_screen_create;
98 break;
99 default:
100 debug_printf("%s: unknown chipset nv%02x\n", __func__,
101 dev->chipset);
102 return NULL;
103 }
104
105 nvws = CALLOC_STRUCT(nouveau_winsys);
106 if (!nvws) {
107 nouveau_device_close(&dev);
108 return NULL;
109 }
110 ws = &nvws->base;
111 ws->destroy = nouveau_drm_destroy_winsys;
112
113 nvws->pscreen = init(ws, dev);
114 if (!nvws->pscreen) {
115 ws->destroy(ws);
116 return NULL;
117 }
118
119 if (arg && arg->mode == DRM_CREATE_DRI1) {
120 struct nouveau_dri *nvdri = dri1->ddx_info;
121 enum pipe_format format;
122
123 if (nvdri->bpp == 16)
124 format = PIPE_FORMAT_B5G6R5_UNORM;
125 else
126 format = PIPE_FORMAT_B8G8R8A8_UNORM;
127
128 nvws->front = dri_surface_from_handle(api, nvws->pscreen,
129 nvdri->front_offset,
130 format, nvdri->width,
131 nvdri->height,
132 nvdri->front_pitch *
133 (nvdri->bpp / 8));
134 if (!nvws->front) {
135 debug_printf("%s: error referencing front buffer\n",
136 __func__);
137 ws->destroy(ws);
138 return NULL;
139 }
140
141 dri1->api = &nouveau_dri1_api;
142 }
143
144 return nvws->pscreen;
145 }
146
147 struct drm_api drm_api_hooks = {
148 .name = "nouveau",
149 .driver_name = "nouveau",
150 .create_screen = nouveau_drm_create_screen,
151 };
152
153 struct drm_api *
154 drm_api_create() {
155 return &drm_api_hooks;
156 }
157