5be5ec5bc24aab1d9a22723b6bdaaeadd74bfdfe
[mesa.git] / src / mesa / drivers / dri / nouveau / nouveau_context.c
1 /*
2 * Copyright (C) 2009-2010 Francisco Jerez.
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *
25 */
26
27 #include <stdbool.h>
28 #include "nouveau_driver.h"
29 #include "nouveau_context.h"
30 #include "nouveau_bufferobj.h"
31 #include "nouveau_fbo.h"
32 #include "nv_object.xml.h"
33
34 #include "main/api_exec.h"
35 #include "main/dd.h"
36 #include "main/framebuffer.h"
37 #include "main/fbobject.h"
38 #include "main/light.h"
39 #include "main/state.h"
40 #include "main/version.h"
41 #include "main/vtxfmt.h"
42 #include "drivers/common/meta.h"
43 #include "drivers/common/driverfuncs.h"
44 #include "swrast/swrast.h"
45 #include "swrast/s_context.h"
46 #include "vbo/vbo.h"
47 #include "tnl/tnl.h"
48 #include "tnl/t_context.h"
49
50 GLboolean
51 nouveau_context_create(gl_api api,
52 const struct gl_config *visual, __DRIcontext *dri_ctx,
53 unsigned major_version,
54 unsigned minor_version,
55 uint32_t flags,
56 bool notify_reset,
57 unsigned *error,
58 void *share_ctx)
59 {
60 __DRIscreen *dri_screen = dri_ctx->driScreenPriv;
61 struct nouveau_screen *screen = dri_screen->driverPrivate;
62 struct nouveau_context *nctx;
63 struct gl_context *ctx;
64
65 if (flags & ~__DRI_CTX_FLAG_DEBUG) {
66 *error = __DRI_CTX_ERROR_UNKNOWN_FLAG;
67 return false;
68 }
69
70 if (notify_reset) {
71 *error = __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE;
72 return false;
73 }
74
75 ctx = screen->driver->context_create(screen, api, visual, share_ctx);
76 if (!ctx) {
77 *error = __DRI_CTX_ERROR_NO_MEMORY;
78 return GL_FALSE;
79 }
80
81 driContextSetFlags(ctx, flags);
82
83 nctx = to_nouveau_context(ctx);
84 nctx->dri_context = dri_ctx;
85 dri_ctx->driverPrivate = ctx;
86
87 _mesa_compute_version(ctx);
88 if (ctx->Version < major_version * 10 + minor_version) {
89 nouveau_context_destroy(dri_ctx);
90 *error = __DRI_CTX_ERROR_BAD_VERSION;
91 return GL_FALSE;
92 }
93
94 /* Exec table initialization requires the version to be computed */
95 _mesa_initialize_dispatch_tables(ctx);
96 _mesa_initialize_vbo_vtxfmt(ctx);
97
98 if (nouveau_bo_new(context_dev(ctx), NOUVEAU_BO_VRAM, 0, 4096,
99 NULL, &nctx->fence)) {
100 nouveau_context_destroy(dri_ctx);
101 *error = __DRI_CTX_ERROR_NO_MEMORY;
102 return GL_FALSE;
103 }
104
105 *error = __DRI_CTX_ERROR_SUCCESS;
106 return GL_TRUE;
107 }
108
109 GLboolean
110 nouveau_context_init(struct gl_context *ctx, gl_api api,
111 struct nouveau_screen *screen,
112 const struct gl_config *visual, struct gl_context *share_ctx)
113 {
114 struct nouveau_context *nctx = to_nouveau_context(ctx);
115 struct dd_function_table functions;
116 int ret;
117
118 nctx->screen = screen;
119 nctx->fallback = HWTNL;
120
121 /* Initialize the function pointers. */
122 _mesa_init_driver_functions(&functions);
123 nouveau_driver_functions_init(&functions);
124 nouveau_bufferobj_functions_init(&functions);
125 nouveau_texture_functions_init(&functions);
126 nouveau_fbo_functions_init(&functions);
127
128 /* Initialize the mesa context. */
129 if (!_mesa_initialize_context(ctx, api, visual, share_ctx, &functions))
130 return GL_FALSE;
131
132 nouveau_state_init(ctx);
133 nouveau_scratch_init(ctx);
134 _mesa_meta_init(ctx);
135 _swrast_CreateContext(ctx);
136 _vbo_CreateContext(ctx);
137 _tnl_CreateContext(ctx);
138 nouveau_span_functions_init(ctx);
139 _mesa_allow_light_in_model(ctx, GL_FALSE);
140
141 /* Allocate a hardware channel. */
142 ret = nouveau_object_new(&context_dev(ctx)->object, 0xbeef0000,
143 NOUVEAU_FIFO_CHANNEL_CLASS,
144 &(struct nv04_fifo){
145 .vram = 0xbeef0201,
146 .gart = 0xbeef0202
147 }, sizeof(struct nv04_fifo), &nctx->hw.chan);
148 if (ret) {
149 nouveau_error("Error initializing the FIFO.\n");
150 return GL_FALSE;
151 }
152
153 /* Allocate a client (thread data) */
154 ret = nouveau_client_new(context_dev(ctx), &nctx->hw.client);
155 if (ret) {
156 nouveau_error("Error creating thread data\n");
157 return GL_FALSE;
158 }
159
160 /* Allocate a push buffer */
161 ret = nouveau_pushbuf_new(nctx->hw.client, nctx->hw.chan, 4,
162 512 * 1024, true, &nctx->hw.pushbuf);
163 if (ret) {
164 nouveau_error("Error allocating DMA push buffer\n");
165 return GL_FALSE;
166 }
167
168 /* Allocate buffer context */
169 ret = nouveau_bufctx_new(nctx->hw.client, 16, &nctx->hw.bufctx);
170 if (ret) {
171 nouveau_error("Error allocating buffer context\n");
172 return GL_FALSE;
173 }
174
175 nctx->hw.pushbuf->user_priv = nctx->hw.bufctx;
176
177 /* Allocate NULL object */
178 ret = nouveau_object_new(nctx->hw.chan, 0x00000000, NV01_NULL_CLASS,
179 NULL, 0, &nctx->hw.null);
180 if (ret) {
181 nouveau_error("Error allocating NULL object\n");
182 return GL_FALSE;
183 }
184
185 /* Enable any supported extensions. */
186 ctx->Extensions.EXT_blend_color = true;
187 ctx->Extensions.EXT_blend_minmax = true;
188 ctx->Extensions.EXT_texture_filter_anisotropic = true;
189 ctx->Extensions.NV_texture_env_combine4 = true;
190 ctx->Const.MaxColorAttachments = 1;
191
192 return GL_TRUE;
193 }
194
195 void
196 nouveau_context_deinit(struct gl_context *ctx)
197 {
198 struct nouveau_context *nctx = to_nouveau_context(ctx);
199
200 if (TNL_CONTEXT(ctx))
201 _tnl_DestroyContext(ctx);
202
203 if (vbo_context(ctx))
204 _vbo_DestroyContext(ctx);
205
206 if (SWRAST_CONTEXT(ctx))
207 _swrast_DestroyContext(ctx);
208
209 if (ctx->Meta)
210 _mesa_meta_free(ctx);
211
212 nouveau_bufctx_del(&nctx->hw.bufctx);
213 nouveau_pushbuf_del(&nctx->hw.pushbuf);
214 nouveau_client_del(&nctx->hw.client);
215 nouveau_object_del(&nctx->hw.chan);
216
217 nouveau_scratch_destroy(ctx);
218 _mesa_free_context_data(ctx);
219 }
220
221 void
222 nouveau_context_destroy(__DRIcontext *dri_ctx)
223 {
224 struct nouveau_context *nctx = dri_ctx->driverPrivate;
225 struct gl_context *ctx = &nctx->base;
226
227 nouveau_bo_ref(NULL, &nctx->fence);
228 context_drv(ctx)->context_destroy(ctx);
229 }
230
231 void
232 nouveau_update_renderbuffers(__DRIcontext *dri_ctx, __DRIdrawable *draw)
233 {
234 struct gl_context *ctx = dri_ctx->driverPrivate;
235 struct nouveau_context *nctx = to_nouveau_context(ctx);
236 __DRIscreen *screen = dri_ctx->driScreenPriv;
237 struct gl_framebuffer *fb = draw->driverPrivate;
238 struct nouveau_framebuffer *nfb = to_nouveau_framebuffer(fb);
239 unsigned int attachments[10];
240 __DRIbuffer *buffers = NULL;
241 int i = 0, count, ret;
242
243 if (draw->lastStamp == draw->dri2.stamp)
244 return;
245 draw->lastStamp = draw->dri2.stamp;
246
247 if (nfb->need_front)
248 attachments[i++] = __DRI_BUFFER_FRONT_LEFT;
249 if (fb->Visual.doubleBufferMode)
250 attachments[i++] = __DRI_BUFFER_BACK_LEFT;
251 if (fb->Visual.haveDepthBuffer && fb->Visual.haveStencilBuffer)
252 attachments[i++] = __DRI_BUFFER_DEPTH_STENCIL;
253 else if (fb->Visual.haveDepthBuffer)
254 attachments[i++] = __DRI_BUFFER_DEPTH;
255 else if (fb->Visual.haveStencilBuffer)
256 attachments[i++] = __DRI_BUFFER_STENCIL;
257
258 buffers = (*screen->dri2.loader->getBuffers)(draw, &draw->w, &draw->h,
259 attachments, i, &count,
260 draw->loaderPrivate);
261 if (buffers == NULL)
262 return;
263
264 for (i = 0; i < count; i++) {
265 struct gl_renderbuffer *rb;
266 struct nouveau_surface *s;
267 uint32_t old_name;
268 int index;
269
270 switch (buffers[i].attachment) {
271 case __DRI_BUFFER_FRONT_LEFT:
272 case __DRI_BUFFER_FAKE_FRONT_LEFT:
273 index = BUFFER_FRONT_LEFT;
274 break;
275 case __DRI_BUFFER_BACK_LEFT:
276 index = BUFFER_BACK_LEFT;
277 break;
278 case __DRI_BUFFER_DEPTH:
279 case __DRI_BUFFER_DEPTH_STENCIL:
280 index = BUFFER_DEPTH;
281 break;
282 case __DRI_BUFFER_STENCIL:
283 index = BUFFER_STENCIL;
284 break;
285 default:
286 assert(0);
287 }
288
289 rb = fb->Attachment[index].Renderbuffer;
290 s = &to_nouveau_renderbuffer(rb)->surface;
291
292 s->width = draw->w;
293 s->height = draw->h;
294 s->pitch = buffers[i].pitch;
295 s->cpp = buffers[i].cpp;
296
297 if (index == BUFFER_DEPTH && s->bo) {
298 ret = nouveau_bo_name_get(s->bo, &old_name);
299 /*
300 * Disable fast Z clears in the next frame, the
301 * depth buffer contents are undefined.
302 */
303 if (!ret && old_name != buffers[i].name)
304 nctx->hierz.clear_seq = 0;
305 }
306
307 nouveau_bo_ref(NULL, &s->bo);
308 ret = nouveau_bo_name_ref(context_dev(ctx),
309 buffers[i].name, &s->bo);
310 assert(!ret);
311 }
312
313 _mesa_resize_framebuffer(ctx, fb, draw->w, draw->h);
314 }
315
316 static void
317 update_framebuffer(__DRIcontext *dri_ctx, __DRIdrawable *draw,
318 int *stamp)
319 {
320 struct gl_context *ctx = dri_ctx->driverPrivate;
321 struct gl_framebuffer *fb = draw->driverPrivate;
322
323 *stamp = draw->dri2.stamp;
324
325 nouveau_update_renderbuffers(dri_ctx, draw);
326 _mesa_resize_framebuffer(ctx, fb, draw->w, draw->h);
327
328 /* Clean up references to the old framebuffer objects. */
329 context_dirty(ctx, FRAMEBUFFER);
330 nouveau_bufctx_reset(to_nouveau_context(ctx)->hw.bufctx, BUFCTX_FB);
331 PUSH_KICK(context_push(ctx));
332 }
333
334 GLboolean
335 nouveau_context_make_current(__DRIcontext *dri_ctx, __DRIdrawable *dri_draw,
336 __DRIdrawable *dri_read)
337 {
338 if (dri_ctx) {
339 struct nouveau_context *nctx = dri_ctx->driverPrivate;
340 struct gl_context *ctx = &nctx->base;
341
342 /* Ask the X server for new renderbuffers. */
343 if (dri_draw->driverPrivate != ctx->WinSysDrawBuffer)
344 update_framebuffer(dri_ctx, dri_draw,
345 &dri_ctx->dri2.draw_stamp);
346
347 if (dri_draw != dri_read &&
348 dri_read->driverPrivate != ctx->WinSysReadBuffer)
349 update_framebuffer(dri_ctx, dri_read,
350 &dri_ctx->dri2.read_stamp);
351
352 /* Pass it down to mesa. */
353 _mesa_make_current(ctx, dri_draw->driverPrivate,
354 dri_read->driverPrivate);
355 _mesa_update_state(ctx);
356
357 } else {
358 _mesa_make_current(NULL, NULL, NULL);
359 }
360
361 return GL_TRUE;
362 }
363
364 GLboolean
365 nouveau_context_unbind(__DRIcontext *dri_ctx)
366 {
367 /* Unset current context and dispatch table */
368 _mesa_make_current(NULL, NULL, NULL);
369
370 return GL_TRUE;
371 }
372
373 void
374 nouveau_fallback(struct gl_context *ctx, enum nouveau_fallback mode)
375 {
376 struct nouveau_context *nctx = to_nouveau_context(ctx);
377
378 nctx->fallback = MAX2(HWTNL, mode);
379
380 if (mode < SWRAST) {
381 nouveau_state_emit(ctx);
382 #if 0
383 nouveau_bo_state_emit(ctx);
384 #endif
385 } else {
386 PUSH_KICK(context_push(ctx));
387 }
388 }
389
390 static void
391 validate_framebuffer(__DRIcontext *dri_ctx, __DRIdrawable *draw,
392 int *stamp)
393 {
394 struct gl_framebuffer *fb = draw->driverPrivate;
395 struct nouveau_framebuffer *nfb = to_nouveau_framebuffer(fb);
396 GLboolean need_front =
397 (fb->_ColorDrawBufferIndexes[0] == BUFFER_FRONT_LEFT ||
398 fb->_ColorReadBufferIndex == BUFFER_FRONT_LEFT);
399
400 if (nfb->need_front != need_front) {
401 nfb->need_front = need_front;
402 dri2InvalidateDrawable(draw);
403 }
404
405 if (draw->dri2.stamp != *stamp)
406 update_framebuffer(dri_ctx, draw, stamp);
407 }
408
409 void
410 nouveau_validate_framebuffer(struct gl_context *ctx)
411 {
412 __DRIcontext *dri_ctx = to_nouveau_context(ctx)->dri_context;
413 __DRIdrawable *dri_draw = dri_ctx->driDrawablePriv;
414 __DRIdrawable *dri_read = dri_ctx->driReadablePriv;
415
416 if (_mesa_is_winsys_fbo(ctx->DrawBuffer))
417 validate_framebuffer(dri_ctx, dri_draw,
418 &dri_ctx->dri2.draw_stamp);
419
420 if (_mesa_is_winsys_fbo(ctx->ReadBuffer))
421 validate_framebuffer(dri_ctx, dri_read,
422 &dri_ctx->dri2.read_stamp);
423
424 if (ctx->NewState & _NEW_BUFFERS)
425 _mesa_update_state(ctx);
426 }