Merge commit 'origin/gallium-master-merge'
[mesa.git] / src / gallium / winsys / drm / nouveau / common / nouveau_context.c
1 #include <pipe/p_defines.h>
2 #include <pipe/p_context.h>
3 #include <pipe/p_screen.h>
4 #include <util/u_memory.h>
5 #include "nouveau_context.h"
6 #include "nouveau_dri.h"
7 #include "nouveau_local.h"
8 #include "nouveau_screen.h"
9 #include "nouveau_winsys_pipe.h"
10
11 static void
12 nouveau_channel_context_destroy(struct nouveau_channel_context *nvc)
13 {
14 nouveau_channel_free(&nvc->channel);
15
16 FREE(nvc);
17 }
18
19 static struct nouveau_channel_context *
20 nouveau_channel_context_create(struct nouveau_device *dev)
21 {
22 struct nouveau_channel_context *nvc;
23 int ret;
24
25 nvc = CALLOC_STRUCT(nouveau_channel_context);
26 if (!nvc)
27 return NULL;
28
29 if ((ret = nouveau_channel_alloc(dev, 0x8003d001, 0x8003d002,
30 &nvc->channel))) {
31 NOUVEAU_ERR("Error creating GPU channel: %d\n", ret);
32 nouveau_channel_context_destroy(nvc);
33 return NULL;
34 }
35
36 nvc->next_handle = 0x77000000;
37 return nvc;
38 }
39
40 int
41 nouveau_context_init(struct nouveau_screen *nv_screen,
42 drm_context_t hHWContext, drmLock *sarea_lock,
43 struct nouveau_context *nv_share,
44 struct nouveau_context *nv)
45 {
46 struct pipe_context *pipe = NULL;
47 struct nouveau_channel_context *nvc = NULL;
48 struct nouveau_device *dev = nv_screen->device;
49 int i;
50
51 switch (dev->chipset & 0xf0) {
52 case 0x00:
53 /* NV04 */
54 case 0x10:
55 case 0x20:
56 /* NV10 */
57 case 0x30:
58 /* NV30 */
59 case 0x40:
60 case 0x60:
61 /* NV40 */
62 case 0x50:
63 case 0x80:
64 case 0x90:
65 /* G80 */
66 break;
67 default:
68 NOUVEAU_ERR("Unsupported chipset: NV%02x\n", dev->chipset);
69 return 1;
70 }
71
72 nv->nv_screen = nv_screen;
73
74 {
75 struct nouveau_device_priv *nvdev = nouveau_device(dev);
76
77 nvdev->ctx = hHWContext;
78 nvdev->lock = sarea_lock;
79 }
80
81 /* Attempt to share a single channel between multiple contexts from
82 * a single process.
83 */
84 nvc = nv_screen->nvc;
85 if (!nvc && nv_share)
86 nvc = nv_share->nvc;
87
88 /*XXX: temporary - disable multi-context/single-channel on pre-NV4x */
89 switch (dev->chipset & 0xf0) {
90 case 0x40:
91 case 0x60:
92 /* NV40 class */
93 case 0x50:
94 case 0x80:
95 case 0x90:
96 /* G80 class */
97 break;
98 default:
99 nvc = NULL;
100 break;
101 }
102
103 if (!nvc) {
104 nvc = nouveau_channel_context_create(dev);
105 if (!nvc) {
106 NOUVEAU_ERR("Failed initialising GPU context\n");
107 return 1;
108 }
109 nv_screen->nvc = nvc;
110 }
111
112 nvc->refcount++;
113 nv->nvc = nvc;
114
115 /* Find a free slot for a pipe context, allocate a new one if needed */
116 nv->pctx_id = -1;
117 for (i = 0; i < nvc->nr_pctx; i++) {
118 if (nvc->pctx[i] == NULL) {
119 nv->pctx_id = i;
120 break;
121 }
122 }
123
124 if (nv->pctx_id < 0) {
125 nv->pctx_id = nvc->nr_pctx++;
126 nvc->pctx =
127 realloc(nvc->pctx,
128 sizeof(struct pipe_context *) * nvc->nr_pctx);
129 }
130
131 /* Create pipe */
132 if (!getenv("NOUVEAU_FORCE_SOFTPIPE")) {
133 struct pipe_screen *pscreen;
134
135 pipe = nouveau_pipe_create(nv);
136 if (!pipe)
137 NOUVEAU_ERR("Couldn't create hw pipe\n");
138 pscreen = nvc->pscreen;
139
140 nv->cap.hw_vertex_buffer =
141 pscreen->get_param(pscreen, NOUVEAU_CAP_HW_VTXBUF);
142 nv->cap.hw_index_buffer =
143 pscreen->get_param(pscreen, NOUVEAU_CAP_HW_IDXBUF);
144 }
145
146 if (!pipe) {
147 NOUVEAU_MSG("Using softpipe\n");
148 pipe = nouveau_create_softpipe(nv);
149 if (!pipe) {
150 NOUVEAU_ERR("Error creating pipe, bailing\n");
151 return 1;
152 }
153 }
154
155 {
156 struct pipe_texture *fb_tex;
157 struct pipe_surface *fb_surf;
158 struct nouveau_pipe_buffer *fb_buf;
159 enum pipe_format format;
160
161 fb_buf = calloc(1, sizeof(struct nouveau_pipe_buffer));
162 fb_buf->base.refcount = 1;
163 fb_buf->base.usage = PIPE_BUFFER_USAGE_PIXEL;
164
165 nouveau_bo_fake(dev, nv_screen->front_offset, NOUVEAU_BO_VRAM,
166 nv_screen->front_pitch*nv_screen->front_height,
167 NULL, &fb_buf->bo);
168
169 if (nv_screen->front_cpp == 4)
170 format = PIPE_FORMAT_A8R8G8B8_UNORM;
171 else
172 format = PIPE_FORMAT_R5G6B5_UNORM;
173
174 fb_surf = nouveau_surface_buffer_ref(nv, &fb_buf->base, format,
175 nv_screen->front_pitch /
176 nv_screen->front_cpp,
177 nv_screen->front_height,
178 nv_screen->front_pitch,
179 &fb_tex);
180
181 nv->frontbuffer = fb_surf;
182 nv->frontbuffer_texture = fb_tex;
183 }
184
185 pipe->priv = nv;
186 return 0;
187 }
188
189 void
190 nouveau_context_cleanup(struct nouveau_context *nv)
191 {
192 struct nouveau_channel_context *nvc = nv->nvc;
193
194 assert(nv);
195
196 if (nv->pctx_id >= 0) {
197 nvc->pctx[nv->pctx_id] = NULL;
198 if (--nvc->refcount <= 0) {
199 nouveau_channel_context_destroy(nvc);
200 nv->nv_screen->nvc = NULL;
201 }
202 }
203
204 /* XXX: Who cleans up the pipe? */
205 }
206