nouveau_context.c revision bde8bd99b64876b47f9d335320eb1ad5b3be8d9d
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
33#include "main/dd.h"
34#include "main/framebuffer.h"
35#include "main/light.h"
36#include "main/state.h"
37#include "drivers/common/meta.h"
38#include "drivers/common/driverfuncs.h"
39#include "swrast/swrast.h"
40#include "swrast/s_context.h"
41#include "vbo/vbo.h"
42#include "tnl/tnl.h"
43#include "tnl/t_context.h"
44
45static void
46nouveau_channel_flush_notify(struct nouveau_channel *chan)
47{
48	struct nouveau_context *nctx = chan->user_private;
49	struct gl_context *ctx = &nctx->base;
50
51	if (nctx->fallback < SWRAST)
52		nouveau_bo_state_emit(ctx);
53}
54
55GLboolean
56nouveau_context_create(gl_api api,
57		       const struct gl_config *visual, __DRIcontext *dri_ctx,
58		       void *share_ctx)
59{
60	__DRIscreen *dri_screen = dri_ctx->driScreenPriv;
61	struct nouveau_screen *screen = dri_screen->private;
62	struct nouveau_context *nctx;
63	struct gl_context *ctx;
64
65	ctx = screen->driver->context_create(screen, visual, share_ctx);
66	if (!ctx)
67		return GL_FALSE;
68
69	nctx = to_nouveau_context(ctx);
70	nctx->dri_context = dri_ctx;
71	dri_ctx->driverPrivate = ctx;
72
73	return GL_TRUE;
74}
75
76GLboolean
77nouveau_context_init(struct gl_context *ctx, struct nouveau_screen *screen,
78		     const struct gl_config *visual, struct gl_context *share_ctx)
79{
80	struct nouveau_context *nctx = to_nouveau_context(ctx);
81	struct dd_function_table functions;
82	int ret;
83
84	nctx->screen = screen;
85	nctx->fallback = HWTNL;
86
87	/* Initialize the function pointers. */
88	_mesa_init_driver_functions(&functions);
89	nouveau_driver_functions_init(&functions);
90	nouveau_bufferobj_functions_init(&functions);
91	nouveau_texture_functions_init(&functions);
92	nouveau_fbo_functions_init(&functions);
93
94	/* Initialize the mesa context. */
95	_mesa_initialize_context(ctx, API_OPENGL, visual,
96                                 share_ctx, &functions, NULL);
97
98	nouveau_state_init(ctx);
99	nouveau_bo_state_init(ctx);
100	nouveau_scratch_init(ctx);
101	_mesa_meta_init(ctx);
102	_swrast_CreateContext(ctx);
103	_vbo_CreateContext(ctx);
104	_tnl_CreateContext(ctx);
105	nouveau_span_functions_init(ctx);
106	_mesa_allow_light_in_model(ctx, GL_FALSE);
107
108	/* Allocate a hardware channel. */
109	ret = nouveau_channel_alloc(context_dev(ctx), 0xbeef0201, 0xbeef0202,
110				    512*1024, &nctx->hw.chan);
111	if (ret) {
112		nouveau_error("Error initializing the FIFO.\n");
113		return GL_FALSE;
114	}
115
116	nctx->hw.chan->flush_notify = nouveau_channel_flush_notify;
117	nctx->hw.chan->user_private = nctx;
118
119	/* Enable any supported extensions. */
120	ctx->Extensions.ARB_texture_mirrored_repeat = true;
121	ctx->Extensions.EXT_blend_color = true;
122	ctx->Extensions.EXT_blend_minmax = true;
123	ctx->Extensions.EXT_blend_subtract = true;
124	ctx->Extensions.EXT_fog_coord = true;
125	ctx->Extensions.EXT_framebuffer_blit = true;
126	ctx->Extensions.EXT_framebuffer_object = true;
127	ctx->Extensions.EXT_packed_depth_stencil = true;
128	ctx->Extensions.EXT_secondary_color = true;
129	ctx->Extensions.EXT_stencil_wrap = true;
130	ctx->Extensions.EXT_texture_filter_anisotropic = true;
131	ctx->Extensions.EXT_texture_lod_bias = true;
132	ctx->Extensions.NV_blend_square = true;
133	ctx->Extensions.NV_texture_env_combine4 = true;
134
135	return GL_TRUE;
136}
137
138void
139nouveau_context_deinit(struct gl_context *ctx)
140{
141	struct nouveau_context *nctx = to_nouveau_context(ctx);
142
143	if (TNL_CONTEXT(ctx))
144		_tnl_DestroyContext(ctx);
145
146	if (vbo_context(ctx))
147		_vbo_DestroyContext(ctx);
148
149	if (SWRAST_CONTEXT(ctx))
150		_swrast_DestroyContext(ctx);
151
152	if (ctx->Meta)
153		_mesa_meta_free(ctx);
154
155	if (nctx->hw.chan)
156		nouveau_channel_free(&nctx->hw.chan);
157
158	nouveau_scratch_destroy(ctx);
159	nouveau_bo_state_destroy(ctx);
160	_mesa_free_context_data(ctx);
161}
162
163void
164nouveau_context_destroy(__DRIcontext *dri_ctx)
165{
166	struct nouveau_context *nctx = dri_ctx->driverPrivate;
167	struct gl_context *ctx = &nctx->base;
168
169	context_drv(ctx)->context_destroy(ctx);
170}
171
172void
173nouveau_update_renderbuffers(__DRIcontext *dri_ctx, __DRIdrawable *draw)
174{
175	struct gl_context *ctx = dri_ctx->driverPrivate;
176	struct nouveau_context *nctx = to_nouveau_context(ctx);
177	__DRIscreen *screen = dri_ctx->driScreenPriv;
178	struct gl_framebuffer *fb = draw->driverPrivate;
179	struct nouveau_framebuffer *nfb = to_nouveau_framebuffer(fb);
180	unsigned int attachments[10];
181	__DRIbuffer *buffers = NULL;
182	int i = 0, count, ret;
183
184	if (draw->lastStamp == *draw->pStamp)
185		return;
186	draw->lastStamp = *draw->pStamp;
187
188	if (nfb->need_front)
189		attachments[i++] = __DRI_BUFFER_FRONT_LEFT;
190	if (fb->Visual.doubleBufferMode)
191		attachments[i++] = __DRI_BUFFER_BACK_LEFT;
192	if (fb->Visual.haveDepthBuffer && fb->Visual.haveStencilBuffer)
193		attachments[i++] = __DRI_BUFFER_DEPTH_STENCIL;
194	else if (fb->Visual.haveDepthBuffer)
195		attachments[i++] = __DRI_BUFFER_DEPTH;
196	else if (fb->Visual.haveStencilBuffer)
197		attachments[i++] = __DRI_BUFFER_STENCIL;
198
199	buffers = (*screen->dri2.loader->getBuffers)(draw, &draw->w, &draw->h,
200						     attachments, i, &count,
201						     draw->loaderPrivate);
202	if (buffers == NULL)
203		return;
204
205	for (i = 0; i < count; i++) {
206		struct gl_renderbuffer *rb;
207		struct nouveau_surface *s;
208		uint32_t old_name;
209		int index;
210
211		switch (buffers[i].attachment) {
212		case __DRI_BUFFER_FRONT_LEFT:
213		case __DRI_BUFFER_FAKE_FRONT_LEFT:
214			index = BUFFER_FRONT_LEFT;
215			break;
216		case __DRI_BUFFER_BACK_LEFT:
217			index = BUFFER_BACK_LEFT;
218			break;
219		case __DRI_BUFFER_DEPTH:
220		case __DRI_BUFFER_DEPTH_STENCIL:
221			index = BUFFER_DEPTH;
222			break;
223		case __DRI_BUFFER_STENCIL:
224			index = BUFFER_STENCIL;
225			break;
226		default:
227			assert(0);
228		}
229
230		rb = fb->Attachment[index].Renderbuffer;
231		s = &to_nouveau_renderbuffer(rb)->surface;
232
233		s->width = draw->w;
234		s->height = draw->h;
235		s->pitch = buffers[i].pitch;
236		s->cpp = buffers[i].cpp;
237
238		if (index == BUFFER_DEPTH && s->bo) {
239			ret = nouveau_bo_handle_get(s->bo, &old_name);
240			/*
241			 * Disable fast Z clears in the next frame, the
242			 * depth buffer contents are undefined.
243			 */
244			if (!ret && old_name != buffers[i].name)
245				nctx->hierz.clear_seq = 0;
246		}
247
248		nouveau_bo_ref(NULL, &s->bo);
249		ret = nouveau_bo_handle_ref(context_dev(ctx),
250					    buffers[i].name, &s->bo);
251		assert(!ret);
252	}
253
254	_mesa_resize_framebuffer(ctx, fb, draw->w, draw->h);
255}
256
257static void
258update_framebuffer(__DRIcontext *dri_ctx, __DRIdrawable *draw,
259		   int *stamp)
260{
261	struct gl_context *ctx = dri_ctx->driverPrivate;
262	struct gl_framebuffer *fb = draw->driverPrivate;
263
264	*stamp = *draw->pStamp;
265
266	nouveau_update_renderbuffers(dri_ctx, draw);
267	_mesa_resize_framebuffer(ctx, fb, draw->w, draw->h);
268
269	/* Clean up references to the old framebuffer objects. */
270	context_dirty(ctx, FRAMEBUFFER);
271	context_bctx(ctx, FRAMEBUFFER);
272	FIRE_RING(context_chan(ctx));
273}
274
275GLboolean
276nouveau_context_make_current(__DRIcontext *dri_ctx, __DRIdrawable *dri_draw,
277			     __DRIdrawable *dri_read)
278{
279	if (dri_ctx) {
280		struct nouveau_context *nctx = dri_ctx->driverPrivate;
281		struct gl_context *ctx = &nctx->base;
282
283		/* Ask the X server for new renderbuffers. */
284		if (dri_draw->driverPrivate != ctx->WinSysDrawBuffer)
285			update_framebuffer(dri_ctx, dri_draw,
286					   &dri_ctx->dri2.draw_stamp);
287
288		if (dri_draw != dri_read &&
289		    dri_read->driverPrivate != ctx->WinSysReadBuffer)
290			update_framebuffer(dri_ctx, dri_read,
291					   &dri_ctx->dri2.read_stamp);
292
293		/* Pass it down to mesa. */
294		_mesa_make_current(ctx, dri_draw->driverPrivate,
295				   dri_read->driverPrivate);
296		_mesa_update_state(ctx);
297
298	} else {
299		_mesa_make_current(NULL, NULL, NULL);
300	}
301
302	return GL_TRUE;
303}
304
305GLboolean
306nouveau_context_unbind(__DRIcontext *dri_ctx)
307{
308	/* Unset current context and dispatch table */
309	_mesa_make_current(NULL, NULL, NULL);
310
311	return GL_TRUE;
312}
313
314void
315nouveau_fallback(struct gl_context *ctx, enum nouveau_fallback mode)
316{
317	struct nouveau_context *nctx = to_nouveau_context(ctx);
318
319	nctx->fallback = MAX2(HWTNL, mode);
320
321	if (mode < SWRAST) {
322		nouveau_state_emit(ctx);
323		nouveau_bo_state_emit(ctx);
324	} else {
325		FIRE_RING(context_chan(ctx));
326	}
327}
328
329static void
330validate_framebuffer(__DRIcontext *dri_ctx, __DRIdrawable *draw,
331		     int *stamp)
332{
333	struct gl_framebuffer *fb = draw->driverPrivate;
334	struct nouveau_framebuffer *nfb = to_nouveau_framebuffer(fb);
335	GLboolean need_front =
336		(fb->_ColorDrawBufferIndexes[0] == BUFFER_FRONT_LEFT ||
337		 fb->_ColorReadBufferIndex == BUFFER_FRONT_LEFT);
338
339	if (nfb->need_front != need_front) {
340		nfb->need_front = need_front;
341		dri2InvalidateDrawable(draw);
342	}
343
344	if (*draw->pStamp != *stamp)
345		update_framebuffer(dri_ctx, draw, stamp);
346}
347
348void
349nouveau_validate_framebuffer(struct gl_context *ctx)
350{
351	__DRIcontext *dri_ctx = to_nouveau_context(ctx)->dri_context;
352	__DRIdrawable *dri_draw = dri_ctx->driDrawablePriv;
353	__DRIdrawable *dri_read = dri_ctx->driReadablePriv;
354
355	if (ctx->DrawBuffer->Name == 0)
356		validate_framebuffer(dri_ctx, dri_draw,
357				     &dri_ctx->dri2.draw_stamp);
358
359	if (ctx->ReadBuffer->Name == 0)
360		validate_framebuffer(dri_ctx, dri_read,
361				     &dri_ctx->dri2.read_stamp);
362
363	if (ctx->NewState & _NEW_BUFFERS)
364		_mesa_update_state(ctx);
365}
366