Merge remote branch 'origin/master' into pipe-video
[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
25 memset(&tmpl, 0, sizeof(tmpl));
26 tmpl.tex_usage = PIPE_TEXTURE_USAGE_PRIMARY;
27 tmpl.target = PIPE_TEXTURE_2D;
28 tmpl.last_level = 0;
29 tmpl.depth0 = 1;
30 tmpl.format = format;
31 tmpl.width0 = width;
32 tmpl.height0 = height;
33
34 pt = api->texture_from_shared_handle(api, pscreen, &tmpl,
35 "front buffer", pitch, handle);
36 if (!pt)
37 return NULL;
38
39 ps = pscreen->get_tex_surface(pscreen, pt, 0, 0, 0,
40 PIPE_BUFFER_USAGE_GPU_READ |
41 PIPE_BUFFER_USAGE_GPU_WRITE);
42
43 /* we don't need the texture from this point on */
44 pipe_texture_reference(&pt, NULL);
45 return ps;
46 }
47
48 static struct pipe_surface *
49 nouveau_dri1_front_surface(struct pipe_screen *screen)
50 {
51 return nouveau_winsys_screen(screen)->front;
52 }
53
54 static struct dri1_api nouveau_dri1_api = {
55 nouveau_dri1_front_surface,
56 };
57
58 static void
59 nouveau_drm_destroy_winsys(struct pipe_winsys *s)
60 {
61 struct nouveau_winsys *nv_winsys = nouveau_winsys(s);
62 struct nouveau_screen *nv_screen= nouveau_screen(nv_winsys->pscreen);
63 nouveau_device_close(&nv_screen->device);
64 FREE(nv_winsys);
65 }
66
67 static struct pipe_screen *
68 nouveau_drm_create_screen(struct drm_api *api, int fd,
69 struct drm_create_screen_arg *arg)
70 {
71 struct dri1_create_screen_arg *dri1 = (void *)arg;
72 struct nouveau_winsys *nvws;
73 struct pipe_winsys *ws;
74 struct nouveau_device *dev = NULL;
75 struct pipe_screen *(*init)(struct pipe_winsys *,
76 struct nouveau_device *);
77 int ret;
78
79 ret = nouveau_device_open_existing(&dev, 0, fd, 0);
80 if (ret)
81 return NULL;
82
83 switch (dev->chipset & 0xf0) {
84 case 0x30:
85 init = nv30_screen_create;
86 break;
87 case 0x40:
88 case 0x60:
89 init = nv40_screen_create;
90 break;
91 case 0x50:
92 case 0x80:
93 case 0x90:
94 case 0xa0:
95 init = nv50_screen_create;
96 break;
97 default:
98 debug_printf("%s: unknown chipset nv%02x\n", __func__,
99 dev->chipset);
100 return NULL;
101 }
102
103 nvws = CALLOC_STRUCT(nouveau_winsys);
104 if (!nvws) {
105 nouveau_device_close(&dev);
106 return NULL;
107 }
108 ws = &nvws->base;
109 ws->destroy = nouveau_drm_destroy_winsys;
110
111 nvws->pscreen = init(ws, dev);
112 if (!nvws->pscreen) {
113 ws->destroy(ws);
114 return NULL;
115 }
116
117 if (arg && arg->mode == DRM_CREATE_DRI1) {
118 struct nouveau_dri *nvdri = dri1->ddx_info;
119 enum pipe_format format;
120
121 if (nvdri->bpp == 16)
122 format = PIPE_FORMAT_B5G6R5_UNORM;
123 else
124 format = PIPE_FORMAT_B8G8R8A8_UNORM;
125
126 nvws->front = dri_surface_from_handle(api, nvws->pscreen,
127 nvdri->front_offset,
128 format, nvdri->width,
129 nvdri->height,
130 nvdri->front_pitch *
131 (nvdri->bpp / 8));
132 if (!nvws->front) {
133 debug_printf("%s: error referencing front buffer\n",
134 __func__);
135 ws->destroy(ws);
136 return NULL;
137 }
138
139 dri1->api = &nouveau_dri1_api;
140 }
141
142 return nvws->pscreen;
143 }
144
145 static struct pipe_texture *
146 nouveau_drm_pt_from_name(struct drm_api *api, struct pipe_screen *pscreen,
147 struct pipe_texture *templ, const char *name,
148 unsigned stride, unsigned handle)
149 {
150 struct nouveau_device *dev = nouveau_screen(pscreen)->device;
151 struct pipe_texture *pt;
152 struct pipe_buffer *pb;
153 int ret;
154
155 pb = CALLOC(1, sizeof(struct pipe_buffer) + sizeof(struct nouveau_bo*));
156 if (!pb)
157 return NULL;
158
159 ret = nouveau_bo_handle_ref(dev, handle, (struct nouveau_bo**)(pb+1));
160 if (ret) {
161 debug_printf("%s: ref name 0x%08x failed with %d\n",
162 __func__, handle, ret);
163 FREE(pb);
164 return NULL;
165 }
166
167 pipe_reference_init(&pb->reference, 1);
168 pb->screen = pscreen;
169 pb->alignment = 0;
170 pb->usage = PIPE_BUFFER_USAGE_GPU_READ_WRITE |
171 PIPE_BUFFER_USAGE_CPU_READ_WRITE;
172 pb->size = nouveau_bo(pb)->size;
173 pt = pscreen->texture_blanket(pscreen, templ, &stride, pb);
174 pipe_buffer_reference(&pb, NULL);
175 return pt;
176 }
177
178 static boolean
179 nouveau_drm_name_from_pt(struct drm_api *api, struct pipe_screen *pscreen,
180 struct pipe_texture *pt, unsigned *stride,
181 unsigned *handle)
182 {
183 struct nouveau_miptree *mt = nouveau_miptree(pt);
184
185 if (!mt || !mt->bo)
186 return false;
187
188 return nouveau_bo_handle_get(mt->bo, handle) == 0;
189 }
190
191 static boolean
192 nouveau_drm_handle_from_pt(struct drm_api *api, struct pipe_screen *pscreen,
193 struct pipe_texture *pt, unsigned *stride,
194 unsigned *handle)
195 {
196 struct nouveau_miptree *mt = nouveau_miptree(pt);
197
198 if (!mt || !mt->bo)
199 return false;
200
201 *handle = mt->bo->handle;
202 *stride = util_format_get_stride(mt->base.format, mt->base.width0);
203 return true;
204 }
205
206 struct drm_api drm_api_hooks = {
207 .name = "nouveau",
208 .driver_name = "nouveau",
209 .create_screen = nouveau_drm_create_screen,
210 .texture_from_shared_handle = nouveau_drm_pt_from_name,
211 .shared_handle_from_texture = nouveau_drm_name_from_pt,
212 .local_handle_from_texture = nouveau_drm_handle_from_pt,
213 };
214
215 struct drm_api *
216 drm_api_create() {
217 return &drm_api_hooks;
218 }
219