2 * Copyright 2010 Christoph Bumiller
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
23 #include "pipe/p_defines.h"
24 #include "util/u_framebuffer.h"
26 #include "nvc0/nvc0_context.h"
27 #include "nvc0/nvc0_screen.h"
28 #include "nvc0/nvc0_resource.h"
31 nvc0_flush(struct pipe_context *pipe,
32 struct pipe_fence_handle **fence,
35 struct nvc0_context *nvc0 = nvc0_context(pipe);
36 struct nouveau_screen *screen = &nvc0->screen->base;
39 nouveau_fence_ref(screen->fence.current, (struct nouveau_fence **)fence);
41 PUSH_KICK(nvc0->base.pushbuf); /* fencing handled in kick_notify */
43 nouveau_context_update_frame_stats(&nvc0->base);
47 nvc0_texture_barrier(struct pipe_context *pipe)
49 struct nouveau_pushbuf *push = nvc0_context(pipe)->base.pushbuf;
51 IMMED_NVC0(push, NVC0_3D(SERIALIZE), 0);
52 IMMED_NVC0(push, NVC0_3D(TEX_CACHE_CTL), 0);
56 nvc0_memory_barrier(struct pipe_context *pipe, unsigned flags)
58 struct nvc0_context *nvc0 = nvc0_context(pipe);
59 struct nouveau_pushbuf *push = nvc0->base.pushbuf;
62 if (flags & PIPE_BARRIER_MAPPED_BUFFER) {
63 for (i = 0; i < nvc0->num_vtxbufs; ++i) {
64 if (!nvc0->vtxbuf[i].buffer)
66 if (nvc0->vtxbuf[i].buffer->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT)
67 nvc0->base.vbo_dirty = true;
70 if (nvc0->idxbuf.buffer &&
71 nvc0->idxbuf.buffer->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT)
72 nvc0->base.vbo_dirty = true;
74 for (s = 0; s < 5 && !nvc0->cb_dirty; ++s) {
75 uint32_t valid = nvc0->constbuf_valid[s];
77 while (valid && !nvc0->cb_dirty) {
78 const unsigned i = ffs(valid) - 1;
79 struct pipe_resource *res;
82 if (nvc0->constbuf[s][i].user)
85 res = nvc0->constbuf[s][i].u.buf;
89 if (res->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT)
90 nvc0->cb_dirty = true;
94 if (flags & PIPE_BARRIER_SHADER_BUFFER) {
95 IMMED_NVC0(push, NVC0_3D(MEM_BARRIER), 0x1011);
100 nvc0_context_unreference_resources(struct nvc0_context *nvc0)
104 nouveau_bufctx_del(&nvc0->bufctx_3d);
105 nouveau_bufctx_del(&nvc0->bufctx);
106 nouveau_bufctx_del(&nvc0->bufctx_cp);
108 util_unreference_framebuffer_state(&nvc0->framebuffer);
110 for (i = 0; i < nvc0->num_vtxbufs; ++i)
111 pipe_resource_reference(&nvc0->vtxbuf[i].buffer, NULL);
113 pipe_resource_reference(&nvc0->idxbuf.buffer, NULL);
115 for (s = 0; s < 6; ++s) {
116 for (i = 0; i < nvc0->num_textures[s]; ++i)
117 pipe_sampler_view_reference(&nvc0->textures[s][i], NULL);
119 for (i = 0; i < NVC0_MAX_PIPE_CONSTBUFS; ++i)
120 if (!nvc0->constbuf[s][i].user)
121 pipe_resource_reference(&nvc0->constbuf[s][i].u.buf, NULL);
124 for (s = 0; s < 2; ++s) {
125 for (i = 0; i < NVC0_MAX_SURFACE_SLOTS; ++i)
126 pipe_surface_reference(&nvc0->surfaces[s][i], NULL);
129 for (s = 0; s < 6; ++s)
130 for (i = 0; i < NVC0_MAX_BUFFERS; ++i)
131 pipe_resource_reference(&nvc0->buffers[s][i].buffer, NULL);
133 for (i = 0; i < nvc0->num_tfbbufs; ++i)
134 pipe_so_target_reference(&nvc0->tfbbuf[i], NULL);
136 for (i = 0; i < nvc0->global_residents.size / sizeof(struct pipe_resource *);
138 struct pipe_resource **res = util_dynarray_element(
139 &nvc0->global_residents, struct pipe_resource *, i);
140 pipe_resource_reference(res, NULL);
142 util_dynarray_fini(&nvc0->global_residents);
145 nvc0->base.pipe.delete_tcs_state(&nvc0->base.pipe, nvc0->tcp_empty);
149 nvc0_destroy(struct pipe_context *pipe)
151 struct nvc0_context *nvc0 = nvc0_context(pipe);
153 if (nvc0->screen->cur_ctx == nvc0) {
154 nvc0->screen->cur_ctx = NULL;
155 nvc0->screen->save_state = nvc0->state;
156 nvc0->screen->save_state.tfb = NULL;
159 /* Unset bufctx, we don't want to revalidate any resources after the flush.
160 * Other contexts will always set their bufctx again on action calls.
162 nouveau_pushbuf_bufctx(nvc0->base.pushbuf, NULL);
163 nouveau_pushbuf_kick(nvc0->base.pushbuf, nvc0->base.pushbuf->channel);
165 nvc0_context_unreference_resources(nvc0);
166 nvc0_blitctx_destroy(nvc0);
168 nouveau_context_destroy(&nvc0->base);
172 nvc0_default_kick_notify(struct nouveau_pushbuf *push)
174 struct nvc0_screen *screen = push->user_priv;
177 nouveau_fence_next(&screen->base);
178 nouveau_fence_update(&screen->base, true);
180 screen->cur_ctx->state.flushed = true;
181 NOUVEAU_DRV_STAT(&screen->base, pushbuf_count, 1);
186 nvc0_invalidate_resource_storage(struct nouveau_context *ctx,
187 struct pipe_resource *res,
190 struct nvc0_context *nvc0 = nvc0_context(&ctx->pipe);
193 if (res->bind & PIPE_BIND_RENDER_TARGET) {
194 for (i = 0; i < nvc0->framebuffer.nr_cbufs; ++i) {
195 if (nvc0->framebuffer.cbufs[i] &&
196 nvc0->framebuffer.cbufs[i]->texture == res) {
197 nvc0->dirty |= NVC0_NEW_FRAMEBUFFER;
198 nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_FB);
204 if (res->bind & PIPE_BIND_DEPTH_STENCIL) {
205 if (nvc0->framebuffer.zsbuf &&
206 nvc0->framebuffer.zsbuf->texture == res) {
207 nvc0->dirty |= NVC0_NEW_FRAMEBUFFER;
208 nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_FB);
214 if (res->target == PIPE_BUFFER) {
215 for (i = 0; i < nvc0->num_vtxbufs; ++i) {
216 if (nvc0->vtxbuf[i].buffer == res) {
217 nvc0->dirty |= NVC0_NEW_ARRAYS;
218 nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_VTX);
224 if (nvc0->idxbuf.buffer == res) {
225 nvc0->dirty |= NVC0_NEW_IDXBUF;
226 nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_IDX);
231 for (s = 0; s < 5; ++s) {
232 for (i = 0; i < nvc0->num_textures[s]; ++i) {
233 if (nvc0->textures[s][i] &&
234 nvc0->textures[s][i]->texture == res) {
235 nvc0->textures_dirty[s] |= 1 << i;
236 nvc0->dirty |= NVC0_NEW_TEXTURES;
237 nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_TEX(s, i));
244 for (s = 0; s < 6; ++s) {
245 for (i = 0; i < NVC0_MAX_PIPE_CONSTBUFS; ++i) {
246 if (!(nvc0->constbuf_valid[s] & (1 << i)))
248 if (!nvc0->constbuf[s][i].user &&
249 nvc0->constbuf[s][i].u.buf == res) {
250 nvc0->constbuf_dirty[s] |= 1 << i;
251 if (unlikely(s == 5)) {
252 nvc0->dirty_cp |= NVC0_NEW_CP_CONSTBUF;
253 nouveau_bufctx_reset(nvc0->bufctx_cp, NVC0_BIND_CP_CB(i));
255 nvc0->dirty |= NVC0_NEW_CONSTBUF;
256 nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_CB(s, i));
264 for (s = 0; s < 5; ++s) {
265 for (i = 0; i < NVC0_MAX_BUFFERS; ++i) {
266 if (nvc0->buffers[s][i].buffer == res) {
267 nvc0->buffers_dirty[s] |= 1 << i;
268 nvc0->dirty |= NVC0_NEW_BUFFERS;
269 nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_BUF);
281 nvc0_context_get_sample_position(struct pipe_context *, unsigned, unsigned,
284 struct pipe_context *
285 nvc0_create(struct pipe_screen *pscreen, void *priv, unsigned ctxflags)
287 struct nvc0_screen *screen = nvc0_screen(pscreen);
288 struct nvc0_context *nvc0;
289 struct pipe_context *pipe;
293 nvc0 = CALLOC_STRUCT(nvc0_context);
296 pipe = &nvc0->base.pipe;
298 if (!nvc0_blitctx_create(nvc0))
301 nvc0->base.pushbuf = screen->base.pushbuf;
302 nvc0->base.client = screen->base.client;
304 ret = nouveau_bufctx_new(screen->base.client, 2, &nvc0->bufctx);
306 ret = nouveau_bufctx_new(screen->base.client, NVC0_BIND_3D_COUNT,
309 ret = nouveau_bufctx_new(screen->base.client, NVC0_BIND_CP_COUNT,
314 nvc0->screen = screen;
315 nvc0->base.screen = &screen->base;
317 pipe->screen = pscreen;
320 pipe->destroy = nvc0_destroy;
322 pipe->draw_vbo = nvc0_draw_vbo;
323 pipe->clear = nvc0_clear;
324 pipe->launch_grid = (nvc0->screen->base.class_3d >= NVE4_3D_CLASS) ?
325 nve4_launch_grid : nvc0_launch_grid;
327 pipe->flush = nvc0_flush;
328 pipe->texture_barrier = nvc0_texture_barrier;
329 pipe->memory_barrier = nvc0_memory_barrier;
330 pipe->get_sample_position = nvc0_context_get_sample_position;
332 nouveau_context_init(&nvc0->base);
333 nvc0_init_query_functions(nvc0);
334 nvc0_init_surface_functions(nvc0);
335 nvc0_init_state_functions(nvc0);
336 nvc0_init_transfer_functions(nvc0);
337 nvc0_init_resource_functions(pipe);
339 nvc0->base.invalidate_resource_storage = nvc0_invalidate_resource_storage;
341 pipe->create_video_codec = nvc0_create_decoder;
342 pipe->create_video_buffer = nvc0_video_buffer_create;
344 /* shader builtin library is per-screen, but we need a context for m2mf */
345 nvc0_program_library_upload(nvc0);
346 nvc0_program_init_tcp_empty(nvc0);
347 if (!nvc0->tcp_empty)
349 /* set the empty tctl prog on next draw in case one is never set */
350 nvc0->dirty |= NVC0_NEW_TCTLPROG;
352 /* now that there are no more opportunities for errors, set the current
353 * context if there isn't already one.
355 if (!screen->cur_ctx) {
356 nvc0->state = screen->save_state;
357 screen->cur_ctx = nvc0;
358 nouveau_pushbuf_bufctx(screen->base.pushbuf, nvc0->bufctx);
360 screen->base.pushbuf->kick_notify = nvc0_default_kick_notify;
362 /* add permanently resident buffers to bufctxts */
364 flags = NV_VRAM_DOMAIN(&screen->base) | NOUVEAU_BO_RD;
366 BCTX_REFN_bo(nvc0->bufctx_3d, SCREEN, flags, screen->text);
367 BCTX_REFN_bo(nvc0->bufctx_3d, SCREEN, flags, screen->uniform_bo);
368 BCTX_REFN_bo(nvc0->bufctx_3d, SCREEN, flags, screen->txc);
369 if (screen->compute) {
370 BCTX_REFN_bo(nvc0->bufctx_cp, CP_SCREEN, flags, screen->text);
371 BCTX_REFN_bo(nvc0->bufctx_cp, CP_SCREEN, flags, screen->txc);
372 BCTX_REFN_bo(nvc0->bufctx_cp, CP_SCREEN, flags, screen->parm);
375 flags = NV_VRAM_DOMAIN(&screen->base) | NOUVEAU_BO_RDWR;
377 if (screen->poly_cache)
378 BCTX_REFN_bo(nvc0->bufctx_3d, SCREEN, flags, screen->poly_cache);
380 BCTX_REFN_bo(nvc0->bufctx_cp, CP_SCREEN, flags, screen->tls);
382 flags = NOUVEAU_BO_GART | NOUVEAU_BO_WR;
384 BCTX_REFN_bo(nvc0->bufctx_3d, SCREEN, flags, screen->fence.bo);
385 BCTX_REFN_bo(nvc0->bufctx, FENCE, flags, screen->fence.bo);
387 BCTX_REFN_bo(nvc0->bufctx_cp, CP_SCREEN, flags, screen->fence.bo);
389 nvc0->base.scratch.bo_size = 2 << 20;
391 memset(nvc0->tex_handles, ~0, sizeof(nvc0->tex_handles));
393 util_dynarray_init(&nvc0->global_residents);
400 nouveau_bufctx_del(&nvc0->bufctx_3d);
402 nouveau_bufctx_del(&nvc0->bufctx_cp);
404 nouveau_bufctx_del(&nvc0->bufctx);
412 nvc0_bufctx_fence(struct nvc0_context *nvc0, struct nouveau_bufctx *bufctx,
415 struct nouveau_list *list = on_flush ? &bufctx->current : &bufctx->pending;
416 struct nouveau_list *it;
417 NOUVEAU_DRV_STAT_IFD(unsigned count = 0);
419 for (it = list->next; it != list; it = it->next) {
420 struct nouveau_bufref *ref = (struct nouveau_bufref *)it;
421 struct nv04_resource *res = ref->priv;
423 nvc0_resource_validate(res, (unsigned)ref->priv_data);
424 NOUVEAU_DRV_STAT_IFD(count++);
426 NOUVEAU_DRV_STAT(&nvc0->screen->base, resource_validate_count, count);
430 nvc0_context_get_sample_position(struct pipe_context *pipe,
431 unsigned sample_count, unsigned sample_index,
434 static const uint8_t ms1[1][2] = { { 0x8, 0x8 } };
435 static const uint8_t ms2[2][2] = {
436 { 0x4, 0x4 }, { 0xc, 0xc } }; /* surface coords (0,0), (1,0) */
437 static const uint8_t ms4[4][2] = {
438 { 0x6, 0x2 }, { 0xe, 0x6 }, /* (0,0), (1,0) */
439 { 0x2, 0xa }, { 0xa, 0xe } }; /* (0,1), (1,1) */
440 static const uint8_t ms8[8][2] = {
441 { 0x1, 0x7 }, { 0x5, 0x3 }, /* (0,0), (1,0) */
442 { 0x3, 0xd }, { 0x7, 0xb }, /* (0,1), (1,1) */
443 { 0x9, 0x5 }, { 0xf, 0x1 }, /* (2,0), (3,0) */
444 { 0xb, 0xf }, { 0xd, 0x9 } }; /* (2,1), (3,1) */
446 /* NOTE: there are alternative modes for MS2 and MS8, currently not used */
447 static const uint8_t ms8_alt[8][2] = {
448 { 0x9, 0x5 }, { 0x7, 0xb }, /* (2,0), (1,1) */
449 { 0xd, 0x9 }, { 0x5, 0x3 }, /* (3,1), (1,0) */
450 { 0x3, 0xd }, { 0x1, 0x7 }, /* (0,1), (0,0) */
451 { 0xb, 0xf }, { 0xf, 0x1 } }; /* (2,1), (3,0) */
454 const uint8_t (*ptr)[2];
456 switch (sample_count) {
458 case 1: ptr = ms1; break;
459 case 2: ptr = ms2; break;
460 case 4: ptr = ms4; break;
461 case 8: ptr = ms8; break;
464 return; /* bad sample count -> undefined locations */
466 xy[0] = ptr[sample_index][0] * 0.0625f;
467 xy[1] = ptr[sample_index][1] * 0.0625f;