181c9d0f2e4a48cf79f585bdae790d65f8faf93c
[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, 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, struct nouveau_screen *screen,
111 const struct gl_config *visual, struct gl_context *share_ctx)
112 {
113 struct nouveau_context *nctx = to_nouveau_context(ctx);
114 struct dd_function_table functions;
115 int ret;
116
117 nctx->screen = screen;
118 nctx->fallback = HWTNL;
119
120 /* Initialize the function pointers. */
121 _mesa_init_driver_functions(&functions);
122 nouveau_driver_functions_init(&functions);
123 nouveau_bufferobj_functions_init(&functions);
124 nouveau_texture_functions_init(&functions);
125 nouveau_fbo_functions_init(&functions);
126
127 /* Initialize the mesa context. */
128 _mesa_initialize_context(ctx, API_OPENGL_COMPAT, visual,
129 share_ctx, &functions);
130
131 nouveau_state_init(ctx);
132 nouveau_scratch_init(ctx);
133 _mesa_meta_init(ctx);
134 _swrast_CreateContext(ctx);
135 _vbo_CreateContext(ctx);
136 _tnl_CreateContext(ctx);
137 nouveau_span_functions_init(ctx);
138 _mesa_allow_light_in_model(ctx, GL_FALSE);
139
140 /* Allocate a hardware channel. */
141 ret = nouveau_object_new(&context_dev(ctx)->object, 0xbeef0000,
142 NOUVEAU_FIFO_CHANNEL_CLASS,
143 &(struct nv04_fifo){
144 .vram = 0xbeef0201,
145 .gart = 0xbeef0202
146 }, sizeof(struct nv04_fifo), &nctx->hw.chan);
147 if (ret) {
148 nouveau_error("Error initializing the FIFO.\n");
149 return GL_FALSE;
150 }
151
152 /* Allocate a client (thread data) */
153 ret = nouveau_client_new(context_dev(ctx), &nctx->hw.client);
154 if (ret) {
155 nouveau_error("Error creating thread data\n");
156 return GL_FALSE;
157 }
158
159 /* Allocate a push buffer */
160 ret = nouveau_pushbuf_new(nctx->hw.client, nctx->hw.chan, 4,
161 512 * 1024, true, &nctx->hw.pushbuf);
162 if (ret) {
163 nouveau_error("Error allocating DMA push buffer\n");
164 return GL_FALSE;
165 }
166
167 /* Allocate buffer context */
168 ret = nouveau_bufctx_new(nctx->hw.client, 16, &nctx->hw.bufctx);
169 if (ret) {
170 nouveau_error("Error allocating buffer context\n");
171 return GL_FALSE;
172 }
173
174 nctx->hw.pushbuf->user_priv = nctx->hw.bufctx;
175
176 /* Allocate NULL object */
177 ret = nouveau_object_new(nctx->hw.chan, 0x00000000, NV01_NULL_CLASS,
178 NULL, 0, &nctx->hw.null);
179 if (ret) {
180 nouveau_error("Error allocating NULL object\n");
181 return GL_FALSE;
182 }
183
184 /* Enable any supported extensions. */
185 ctx->Extensions.EXT_blend_color = true;
186 ctx->Extensions.EXT_blend_minmax = true;
187 ctx->Extensions.EXT_framebuffer_blit = true;
188 ctx->Extensions.EXT_texture_filter_anisotropic = true;
189 ctx->Extensions.NV_texture_env_combine4 = true;
190
191 return GL_TRUE;
192 }
193
194 void
195 nouveau_context_deinit(struct gl_context *ctx)
196 {
197 struct nouveau_context *nctx = to_nouveau_context(ctx);
198
199 if (TNL_CONTEXT(ctx))
200 _tnl_DestroyContext(ctx);
201
202 if (vbo_context(ctx))
203 _vbo_DestroyContext(ctx);
204
205 if (SWRAST_CONTEXT(ctx))
206 _swrast_DestroyContext(ctx);
207
208 if (ctx->Meta)
209 _mesa_meta_free(ctx);
210
211 nouveau_bufctx_del(&nctx->hw.bufctx);
212 nouveau_pushbuf_del(&nctx->hw.pushbuf);
213 nouveau_client_del(&nctx->hw.client);
214 nouveau_object_del(&nctx->hw.chan);
215
216 nouveau_scratch_destroy(ctx);
217 _mesa_free_context_data(ctx);
218 }
219
220 void
221 nouveau_context_destroy(__DRIcontext *dri_ctx)
222 {
223 struct nouveau_context *nctx = dri_ctx->driverPrivate;
224 struct gl_context *ctx = &nctx->base;
225
226 nouveau_bo_ref(NULL, &nctx->fence);
227 context_drv(ctx)->context_destroy(ctx);
228 }
229
230 void
231 nouveau_update_renderbuffers(__DRIcontext *dri_ctx, __DRIdrawable *draw)
232 {
233 struct gl_context *ctx = dri_ctx->driverPrivate;
234 struct nouveau_context *nctx = to_nouveau_context(ctx);
235 __DRIscreen *screen = dri_ctx->driScreenPriv;
236 struct gl_framebuffer *fb = draw->driverPrivate;
237 struct nouveau_framebuffer *nfb = to_nouveau_framebuffer(fb);
238 unsigned int attachments[10];
239 __DRIbuffer *buffers = NULL;
240 int i = 0, count, ret;
241
242 if (draw->lastStamp == draw->dri2.stamp)
243 return;
244 draw->lastStamp = draw->dri2.stamp;
245
246 if (nfb->need_front)
247 attachments[i++] = __DRI_BUFFER_FRONT_LEFT;
248 if (fb->Visual.doubleBufferMode)
249 attachments[i++] = __DRI_BUFFER_BACK_LEFT;
250 if (fb->Visual.haveDepthBuffer && fb->Visual.haveStencilBuffer)
251 attachments[i++] = __DRI_BUFFER_DEPTH_STENCIL;
252 else if (fb->Visual.haveDepthBuffer)
253 attachments[i++] = __DRI_BUFFER_DEPTH;
254 else if (fb->Visual.haveStencilBuffer)
255 attachments[i++] = __DRI_BUFFER_STENCIL;
256
257 buffers = (*screen->dri2.loader->getBuffers)(draw, &draw->w, &draw->h,
258 attachments, i, &count,
259 draw->loaderPrivate);
260 if (buffers == NULL)
261 return;
262
263 for (i = 0; i < count; i++) {
264 struct gl_renderbuffer *rb;
265 struct nouveau_surface *s;
266 uint32_t old_name;
267 int index;
268
269 switch (buffers[i].attachment) {
270 case __DRI_BUFFER_FRONT_LEFT:
271 case __DRI_BUFFER_FAKE_FRONT_LEFT:
272 index = BUFFER_FRONT_LEFT;
273 break;
274 case __DRI_BUFFER_BACK_LEFT:
275 index = BUFFER_BACK_LEFT;
276 break;
277 case __DRI_BUFFER_DEPTH:
278 case __DRI_BUFFER_DEPTH_STENCIL:
279 index = BUFFER_DEPTH;
280 break;
281 case __DRI_BUFFER_STENCIL:
282 index = BUFFER_STENCIL;
283 break;
284 default:
285 assert(0);
286 }
287
288 rb = fb->Attachment[index].Renderbuffer;
289 s = &to_nouveau_renderbuffer(rb)->surface;
290
291 s->width = draw->w;
292 s->height = draw->h;
293 s->pitch = buffers[i].pitch;
294 s->cpp = buffers[i].cpp;
295
296 if (index == BUFFER_DEPTH && s->bo) {
297 ret = nouveau_bo_name_get(s->bo, &old_name);
298 /*
299 * Disable fast Z clears in the next frame, the
300 * depth buffer contents are undefined.
301 */
302 if (!ret && old_name != buffers[i].name)
303 nctx->hierz.clear_seq = 0;
304 }
305
306 nouveau_bo_ref(NULL, &s->bo);
307 ret = nouveau_bo_name_ref(context_dev(ctx),
308 buffers[i].name, &s->bo);
309 assert(!ret);
310 }
311
312 _mesa_resize_framebuffer(ctx, fb, draw->w, draw->h);
313 }
314
315 static void
316 update_framebuffer(__DRIcontext *dri_ctx, __DRIdrawable *draw,
317 int *stamp)
318 {
319 struct gl_context *ctx = dri_ctx->driverPrivate;
320 struct gl_framebuffer *fb = draw->driverPrivate;
321
322 *stamp = draw->dri2.stamp;
323
324 nouveau_update_renderbuffers(dri_ctx, draw);
325 _mesa_resize_framebuffer(ctx, fb, draw->w, draw->h);
326
327 /* Clean up references to the old framebuffer objects. */
328 context_dirty(ctx, FRAMEBUFFER);
329 nouveau_bufctx_reset(to_nouveau_context(ctx)->hw.bufctx, BUFCTX_FB);
330 PUSH_KICK(context_push(ctx));
331 }
332
333 GLboolean
334 nouveau_context_make_current(__DRIcontext *dri_ctx, __DRIdrawable *dri_draw,
335 __DRIdrawable *dri_read)
336 {
337 if (dri_ctx) {
338 struct nouveau_context *nctx = dri_ctx->driverPrivate;
339 struct gl_context *ctx = &nctx->base;
340
341 /* Ask the X server for new renderbuffers. */
342 if (dri_draw->driverPrivate != ctx->WinSysDrawBuffer)
343 update_framebuffer(dri_ctx, dri_draw,
344 &dri_ctx->dri2.draw_stamp);
345
346 if (dri_draw != dri_read &&
347 dri_read->driverPrivate != ctx->WinSysReadBuffer)
348 update_framebuffer(dri_ctx, dri_read,
349 &dri_ctx->dri2.read_stamp);
350
351 /* Pass it down to mesa. */
352 _mesa_make_current(ctx, dri_draw->driverPrivate,
353 dri_read->driverPrivate);
354 _mesa_update_state(ctx);
355
356 } else {
357 _mesa_make_current(NULL, NULL, NULL);
358 }
359
360 return GL_TRUE;
361 }
362
363 GLboolean
364 nouveau_context_unbind(__DRIcontext *dri_ctx)
365 {
366 /* Unset current context and dispatch table */
367 _mesa_make_current(NULL, NULL, NULL);
368
369 return GL_TRUE;
370 }
371
372 void
373 nouveau_fallback(struct gl_context *ctx, enum nouveau_fallback mode)
374 {
375 struct nouveau_context *nctx = to_nouveau_context(ctx);
376
377 nctx->fallback = MAX2(HWTNL, mode);
378
379 if (mode < SWRAST) {
380 nouveau_state_emit(ctx);
381 #if 0
382 nouveau_bo_state_emit(ctx);
383 #endif
384 } else {
385 PUSH_KICK(context_push(ctx));
386 }
387 }
388
389 static void
390 validate_framebuffer(__DRIcontext *dri_ctx, __DRIdrawable *draw,
391 int *stamp)
392 {
393 struct gl_framebuffer *fb = draw->driverPrivate;
394 struct nouveau_framebuffer *nfb = to_nouveau_framebuffer(fb);
395 GLboolean need_front =
396 (fb->_ColorDrawBufferIndexes[0] == BUFFER_FRONT_LEFT ||
397 fb->_ColorReadBufferIndex == BUFFER_FRONT_LEFT);
398
399 if (nfb->need_front != need_front) {
400 nfb->need_front = need_front;
401 dri2InvalidateDrawable(draw);
402 }
403
404 if (draw->dri2.stamp != *stamp)
405 update_framebuffer(dri_ctx, draw, stamp);
406 }
407
408 void
409 nouveau_validate_framebuffer(struct gl_context *ctx)
410 {
411 __DRIcontext *dri_ctx = to_nouveau_context(ctx)->dri_context;
412 __DRIdrawable *dri_draw = dri_ctx->driDrawablePriv;
413 __DRIdrawable *dri_read = dri_ctx->driReadablePriv;
414
415 if (_mesa_is_winsys_fbo(ctx->DrawBuffer))
416 validate_framebuffer(dri_ctx, dri_draw,
417 &dri_ctx->dri2.draw_stamp);
418
419 if (_mesa_is_winsys_fbo(ctx->ReadBuffer))
420 validate_framebuffer(dri_ctx, dri_read,
421 &dri_ctx->dri2.read_stamp);
422
423 if (ctx->NewState & _NEW_BUFFERS)
424 _mesa_update_state(ctx);
425 }