nouveau: 3d textures are unsupported, limit 3d levels to 1
[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 /* This effectively disables 3D textures */
193 ctx->Const.Max3DTextureLevels = 1;
194
195 return GL_TRUE;
196 }
197
198 void
199 nouveau_context_deinit(struct gl_context *ctx)
200 {
201 struct nouveau_context *nctx = to_nouveau_context(ctx);
202
203 if (TNL_CONTEXT(ctx))
204 _tnl_DestroyContext(ctx);
205
206 if (vbo_context(ctx))
207 _vbo_DestroyContext(ctx);
208
209 if (SWRAST_CONTEXT(ctx))
210 _swrast_DestroyContext(ctx);
211
212 if (ctx->Meta)
213 _mesa_meta_free(ctx);
214
215 nouveau_bufctx_del(&nctx->hw.bufctx);
216 nouveau_pushbuf_del(&nctx->hw.pushbuf);
217 nouveau_client_del(&nctx->hw.client);
218 nouveau_object_del(&nctx->hw.chan);
219
220 nouveau_scratch_destroy(ctx);
221 _mesa_free_context_data(ctx);
222 }
223
224 void
225 nouveau_context_destroy(__DRIcontext *dri_ctx)
226 {
227 struct nouveau_context *nctx = dri_ctx->driverPrivate;
228 struct gl_context *ctx = &nctx->base;
229
230 nouveau_bo_ref(NULL, &nctx->fence);
231 context_drv(ctx)->context_destroy(ctx);
232 }
233
234 void
235 nouveau_update_renderbuffers(__DRIcontext *dri_ctx, __DRIdrawable *draw)
236 {
237 struct gl_context *ctx = dri_ctx->driverPrivate;
238 struct nouveau_context *nctx = to_nouveau_context(ctx);
239 __DRIscreen *screen = dri_ctx->driScreenPriv;
240 struct gl_framebuffer *fb = draw->driverPrivate;
241 struct nouveau_framebuffer *nfb = to_nouveau_framebuffer(fb);
242 unsigned int attachments[10];
243 __DRIbuffer *buffers = NULL;
244 int i = 0, count, ret;
245
246 if (draw->lastStamp == draw->dri2.stamp)
247 return;
248 draw->lastStamp = draw->dri2.stamp;
249
250 if (nfb->need_front)
251 attachments[i++] = __DRI_BUFFER_FRONT_LEFT;
252 if (fb->Visual.doubleBufferMode)
253 attachments[i++] = __DRI_BUFFER_BACK_LEFT;
254 if (fb->Visual.haveDepthBuffer && fb->Visual.haveStencilBuffer)
255 attachments[i++] = __DRI_BUFFER_DEPTH_STENCIL;
256 else if (fb->Visual.haveDepthBuffer)
257 attachments[i++] = __DRI_BUFFER_DEPTH;
258 else if (fb->Visual.haveStencilBuffer)
259 attachments[i++] = __DRI_BUFFER_STENCIL;
260
261 buffers = (*screen->dri2.loader->getBuffers)(draw, &draw->w, &draw->h,
262 attachments, i, &count,
263 draw->loaderPrivate);
264 if (buffers == NULL)
265 return;
266
267 for (i = 0; i < count; i++) {
268 struct gl_renderbuffer *rb;
269 struct nouveau_surface *s;
270 uint32_t old_name;
271 int index;
272
273 switch (buffers[i].attachment) {
274 case __DRI_BUFFER_FRONT_LEFT:
275 case __DRI_BUFFER_FAKE_FRONT_LEFT:
276 index = BUFFER_FRONT_LEFT;
277 break;
278 case __DRI_BUFFER_BACK_LEFT:
279 index = BUFFER_BACK_LEFT;
280 break;
281 case __DRI_BUFFER_DEPTH:
282 case __DRI_BUFFER_DEPTH_STENCIL:
283 index = BUFFER_DEPTH;
284 break;
285 case __DRI_BUFFER_STENCIL:
286 index = BUFFER_STENCIL;
287 break;
288 default:
289 assert(0);
290 }
291
292 rb = fb->Attachment[index].Renderbuffer;
293 s = &to_nouveau_renderbuffer(rb)->surface;
294
295 s->width = draw->w;
296 s->height = draw->h;
297 s->pitch = buffers[i].pitch;
298 s->cpp = buffers[i].cpp;
299
300 if (index == BUFFER_DEPTH && s->bo) {
301 ret = nouveau_bo_name_get(s->bo, &old_name);
302 /*
303 * Disable fast Z clears in the next frame, the
304 * depth buffer contents are undefined.
305 */
306 if (!ret && old_name != buffers[i].name)
307 nctx->hierz.clear_seq = 0;
308 }
309
310 nouveau_bo_ref(NULL, &s->bo);
311 ret = nouveau_bo_name_ref(context_dev(ctx),
312 buffers[i].name, &s->bo);
313 assert(!ret);
314 }
315
316 _mesa_resize_framebuffer(ctx, fb, draw->w, draw->h);
317 }
318
319 static void
320 update_framebuffer(__DRIcontext *dri_ctx, __DRIdrawable *draw,
321 int *stamp)
322 {
323 struct gl_context *ctx = dri_ctx->driverPrivate;
324 struct gl_framebuffer *fb = draw->driverPrivate;
325
326 *stamp = draw->dri2.stamp;
327
328 nouveau_update_renderbuffers(dri_ctx, draw);
329 _mesa_resize_framebuffer(ctx, fb, draw->w, draw->h);
330
331 /* Clean up references to the old framebuffer objects. */
332 context_dirty(ctx, FRAMEBUFFER);
333 nouveau_bufctx_reset(to_nouveau_context(ctx)->hw.bufctx, BUFCTX_FB);
334 PUSH_KICK(context_push(ctx));
335 }
336
337 GLboolean
338 nouveau_context_make_current(__DRIcontext *dri_ctx, __DRIdrawable *dri_draw,
339 __DRIdrawable *dri_read)
340 {
341 if (dri_ctx) {
342 struct nouveau_context *nctx = dri_ctx->driverPrivate;
343 struct gl_context *ctx = &nctx->base;
344
345 /* Ask the X server for new renderbuffers. */
346 if (dri_draw->driverPrivate != ctx->WinSysDrawBuffer)
347 update_framebuffer(dri_ctx, dri_draw,
348 &dri_ctx->dri2.draw_stamp);
349
350 if (dri_draw != dri_read &&
351 dri_read->driverPrivate != ctx->WinSysReadBuffer)
352 update_framebuffer(dri_ctx, dri_read,
353 &dri_ctx->dri2.read_stamp);
354
355 /* Pass it down to mesa. */
356 _mesa_make_current(ctx, dri_draw->driverPrivate,
357 dri_read->driverPrivate);
358 _mesa_update_state(ctx);
359
360 } else {
361 _mesa_make_current(NULL, NULL, NULL);
362 }
363
364 return GL_TRUE;
365 }
366
367 GLboolean
368 nouveau_context_unbind(__DRIcontext *dri_ctx)
369 {
370 /* Unset current context and dispatch table */
371 _mesa_make_current(NULL, NULL, NULL);
372
373 return GL_TRUE;
374 }
375
376 void
377 nouveau_fallback(struct gl_context *ctx, enum nouveau_fallback mode)
378 {
379 struct nouveau_context *nctx = to_nouveau_context(ctx);
380
381 nctx->fallback = MAX2(HWTNL, mode);
382
383 if (mode < SWRAST) {
384 nouveau_state_emit(ctx);
385 #if 0
386 nouveau_bo_state_emit(ctx);
387 #endif
388 } else {
389 PUSH_KICK(context_push(ctx));
390 }
391 }
392
393 static void
394 validate_framebuffer(__DRIcontext *dri_ctx, __DRIdrawable *draw,
395 int *stamp)
396 {
397 struct gl_framebuffer *fb = draw->driverPrivate;
398 struct nouveau_framebuffer *nfb = to_nouveau_framebuffer(fb);
399 GLboolean need_front =
400 (fb->_ColorDrawBufferIndexes[0] == BUFFER_FRONT_LEFT ||
401 fb->_ColorReadBufferIndex == BUFFER_FRONT_LEFT);
402
403 if (nfb->need_front != need_front) {
404 nfb->need_front = need_front;
405 dri2InvalidateDrawable(draw);
406 }
407
408 if (draw->dri2.stamp != *stamp)
409 update_framebuffer(dri_ctx, draw, stamp);
410 }
411
412 void
413 nouveau_validate_framebuffer(struct gl_context *ctx)
414 {
415 __DRIcontext *dri_ctx = to_nouveau_context(ctx)->dri_context;
416 __DRIdrawable *dri_draw = dri_ctx->driDrawablePriv;
417 __DRIdrawable *dri_read = dri_ctx->driReadablePriv;
418
419 if (_mesa_is_winsys_fbo(ctx->DrawBuffer))
420 validate_framebuffer(dri_ctx, dri_draw,
421 &dri_ctx->dri2.draw_stamp);
422
423 if (_mesa_is_winsys_fbo(ctx->ReadBuffer))
424 validate_framebuffer(dri_ctx, dri_read,
425 &dri_ctx->dri2.read_stamp);
426
427 if (ctx->NewState & _NEW_BUFFERS)
428 _mesa_update_state(ctx);
429 }