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