1/* 2 * Copyright 2010 Christoph Bumiller 3 * 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: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 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. 21 */ 22 23#include "pipe/p_defines.h" 24#include "util/u_framebuffer.h" 25 26#include "nv50/nv50_context.h" 27#include "nv50/nv50_screen.h" 28#include "nv50/nv50_resource.h" 29 30static void 31nv50_flush(struct pipe_context *pipe, 32 struct pipe_fence_handle **fence, 33 unsigned flags) 34{ 35 struct nouveau_screen *screen = nouveau_screen(pipe->screen); 36 37 if (fence) 38 nouveau_fence_ref(screen->fence.current, (struct nouveau_fence **)fence); 39 40 PUSH_KICK(screen->pushbuf); 41 42 nouveau_context_update_frame_stats(nouveau_context(pipe)); 43} 44 45static void 46nv50_texture_barrier(struct pipe_context *pipe, unsigned flags) 47{ 48 struct nouveau_pushbuf *push = nv50_context(pipe)->base.pushbuf; 49 50 BEGIN_NV04(push, SUBC_3D(NV50_GRAPH_SERIALIZE), 1); 51 PUSH_DATA (push, 0); 52 BEGIN_NV04(push, NV50_3D(TEX_CACHE_CTL), 1); 53 PUSH_DATA (push, 0x20); 54} 55 56static void 57nv50_memory_barrier(struct pipe_context *pipe, unsigned flags) 58{ 59 struct nv50_context *nv50 = nv50_context(pipe); 60 int i, s; 61 62 if (flags & PIPE_BARRIER_MAPPED_BUFFER) { 63 for (i = 0; i < nv50->num_vtxbufs; ++i) { 64 if (!nv50->vtxbuf[i].buffer) 65 continue; 66 if (nv50->vtxbuf[i].buffer->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT) 67 nv50->base.vbo_dirty = true; 68 } 69 70 if (nv50->idxbuf.buffer && 71 nv50->idxbuf.buffer->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT) 72 nv50->base.vbo_dirty = true; 73 74 for (s = 0; s < 3 && !nv50->cb_dirty; ++s) { 75 uint32_t valid = nv50->constbuf_valid[s]; 76 77 while (valid && !nv50->cb_dirty) { 78 const unsigned i = ffs(valid) - 1; 79 struct pipe_resource *res; 80 81 valid &= ~(1 << i); 82 if (nv50->constbuf[s][i].user) 83 continue; 84 85 res = nv50->constbuf[s][i].u.buf; 86 if (!res) 87 continue; 88 89 if (res->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT) 90 nv50->cb_dirty = true; 91 } 92 } 93 } 94} 95 96static void 97nv50_emit_string_marker(struct pipe_context *pipe, const char *str, int len) 98{ 99 struct nouveau_pushbuf *push = nv50_context(pipe)->base.pushbuf; 100 int string_words = len / 4; 101 int data_words; 102 103 if (len <= 0) 104 return; 105 string_words = MIN2(string_words, NV04_PFIFO_MAX_PACKET_LEN); 106 if (string_words == NV04_PFIFO_MAX_PACKET_LEN) 107 data_words = string_words; 108 else 109 data_words = string_words + !!(len & 3); 110 BEGIN_NI04(push, SUBC_3D(NV04_GRAPH_NOP), data_words); 111 if (string_words) 112 PUSH_DATAp(push, str, string_words); 113 if (string_words != data_words) { 114 int data = 0; 115 memcpy(&data, &str[string_words * 4], len & 3); 116 PUSH_DATA (push, data); 117 } 118} 119 120void 121nv50_default_kick_notify(struct nouveau_pushbuf *push) 122{ 123 struct nv50_screen *screen = push->user_priv; 124 125 if (screen) { 126 nouveau_fence_next(&screen->base); 127 nouveau_fence_update(&screen->base, true); 128 if (screen->cur_ctx) 129 screen->cur_ctx->state.flushed = true; 130 } 131} 132 133static void 134nv50_context_unreference_resources(struct nv50_context *nv50) 135{ 136 unsigned s, i; 137 138 nouveau_bufctx_del(&nv50->bufctx_3d); 139 nouveau_bufctx_del(&nv50->bufctx); 140 nouveau_bufctx_del(&nv50->bufctx_cp); 141 142 util_unreference_framebuffer_state(&nv50->framebuffer); 143 144 assert(nv50->num_vtxbufs <= PIPE_MAX_ATTRIBS); 145 for (i = 0; i < nv50->num_vtxbufs; ++i) 146 pipe_resource_reference(&nv50->vtxbuf[i].buffer, NULL); 147 148 pipe_resource_reference(&nv50->idxbuf.buffer, NULL); 149 150 for (s = 0; s < 3; ++s) { 151 assert(nv50->num_textures[s] <= PIPE_MAX_SAMPLERS); 152 for (i = 0; i < nv50->num_textures[s]; ++i) 153 pipe_sampler_view_reference(&nv50->textures[s][i], NULL); 154 155 for (i = 0; i < NV50_MAX_PIPE_CONSTBUFS; ++i) 156 if (!nv50->constbuf[s][i].user) 157 pipe_resource_reference(&nv50->constbuf[s][i].u.buf, NULL); 158 } 159 160 for (i = 0; i < nv50->global_residents.size / sizeof(struct pipe_resource *); 161 ++i) { 162 struct pipe_resource **res = util_dynarray_element( 163 &nv50->global_residents, struct pipe_resource *, i); 164 pipe_resource_reference(res, NULL); 165 } 166 util_dynarray_fini(&nv50->global_residents); 167} 168 169static void 170nv50_destroy(struct pipe_context *pipe) 171{ 172 struct nv50_context *nv50 = nv50_context(pipe); 173 174 if (nv50->screen->cur_ctx == nv50) { 175 nv50->screen->cur_ctx = NULL; 176 /* Save off the state in case another context gets created */ 177 nv50->screen->save_state = nv50->state; 178 } 179 nouveau_pushbuf_bufctx(nv50->base.pushbuf, NULL); 180 nouveau_pushbuf_kick(nv50->base.pushbuf, nv50->base.pushbuf->channel); 181 182 nv50_context_unreference_resources(nv50); 183 184 FREE(nv50->blit); 185 186 nouveau_context_destroy(&nv50->base); 187} 188 189static int 190nv50_invalidate_resource_storage(struct nouveau_context *ctx, 191 struct pipe_resource *res, 192 int ref) 193{ 194 struct nv50_context *nv50 = nv50_context(&ctx->pipe); 195 unsigned bind = res->bind ? res->bind : PIPE_BIND_VERTEX_BUFFER; 196 unsigned s, i; 197 198 if (bind & PIPE_BIND_RENDER_TARGET) { 199 assert(nv50->framebuffer.nr_cbufs <= PIPE_MAX_COLOR_BUFS); 200 for (i = 0; i < nv50->framebuffer.nr_cbufs; ++i) { 201 if (nv50->framebuffer.cbufs[i] && 202 nv50->framebuffer.cbufs[i]->texture == res) { 203 nv50->dirty_3d |= NV50_NEW_3D_FRAMEBUFFER; 204 nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_3D_FB); 205 if (!--ref) 206 return ref; 207 } 208 } 209 } 210 if (bind & PIPE_BIND_DEPTH_STENCIL) { 211 if (nv50->framebuffer.zsbuf && 212 nv50->framebuffer.zsbuf->texture == res) { 213 nv50->dirty_3d |= NV50_NEW_3D_FRAMEBUFFER; 214 nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_3D_FB); 215 if (!--ref) 216 return ref; 217 } 218 } 219 220 if (bind & (PIPE_BIND_VERTEX_BUFFER | 221 PIPE_BIND_INDEX_BUFFER | 222 PIPE_BIND_CONSTANT_BUFFER | 223 PIPE_BIND_STREAM_OUTPUT | 224 PIPE_BIND_SAMPLER_VIEW)) { 225 226 assert(nv50->num_vtxbufs <= PIPE_MAX_ATTRIBS); 227 for (i = 0; i < nv50->num_vtxbufs; ++i) { 228 if (nv50->vtxbuf[i].buffer == res) { 229 nv50->dirty_3d |= NV50_NEW_3D_ARRAYS; 230 nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_3D_VERTEX); 231 if (!--ref) 232 return ref; 233 } 234 } 235 236 if (nv50->idxbuf.buffer == res) { 237 /* Just rebind to the bufctx as there is no separate dirty bit */ 238 nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_3D_INDEX); 239 BCTX_REFN(nv50->bufctx_3d, 3D_INDEX, nv04_resource(res), RD); 240 if (!--ref) 241 return ref; 242 } 243 244 for (s = 0; s < 3; ++s) { 245 assert(nv50->num_textures[s] <= PIPE_MAX_SAMPLERS); 246 for (i = 0; i < nv50->num_textures[s]; ++i) { 247 if (nv50->textures[s][i] && 248 nv50->textures[s][i]->texture == res) { 249 nv50->dirty_3d |= NV50_NEW_3D_TEXTURES; 250 nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_3D_TEXTURES); 251 if (!--ref) 252 return ref; 253 } 254 } 255 } 256 257 for (s = 0; s < 3; ++s) { 258 for (i = 0; i < NV50_MAX_PIPE_CONSTBUFS; ++i) { 259 if (!(nv50->constbuf_valid[s] & (1 << i))) 260 continue; 261 if (!nv50->constbuf[s][i].user && 262 nv50->constbuf[s][i].u.buf == res) { 263 nv50->dirty_3d |= NV50_NEW_3D_CONSTBUF; 264 nv50->constbuf_dirty[s] |= 1 << i; 265 nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_3D_CB(s, i)); 266 if (!--ref) 267 return ref; 268 } 269 } 270 } 271 } 272 273 return ref; 274} 275 276static void 277nv50_context_get_sample_position(struct pipe_context *, unsigned, unsigned, 278 float *); 279 280struct pipe_context * 281nv50_create(struct pipe_screen *pscreen, void *priv, unsigned ctxflags) 282{ 283 struct nv50_screen *screen = nv50_screen(pscreen); 284 struct nv50_context *nv50; 285 struct pipe_context *pipe; 286 int ret; 287 uint32_t flags; 288 289 nv50 = CALLOC_STRUCT(nv50_context); 290 if (!nv50) 291 return NULL; 292 pipe = &nv50->base.pipe; 293 294 if (!nv50_blitctx_create(nv50)) 295 goto out_err; 296 297 nv50->base.pushbuf = screen->base.pushbuf; 298 nv50->base.client = screen->base.client; 299 300 ret = nouveau_bufctx_new(screen->base.client, 2, &nv50->bufctx); 301 if (!ret) 302 ret = nouveau_bufctx_new(screen->base.client, NV50_BIND_3D_COUNT, 303 &nv50->bufctx_3d); 304 if (!ret) 305 ret = nouveau_bufctx_new(screen->base.client, NV50_BIND_CP_COUNT, 306 &nv50->bufctx_cp); 307 if (ret) 308 goto out_err; 309 310 nv50->base.screen = &screen->base; 311 nv50->base.copy_data = nv50_m2mf_copy_linear; 312 nv50->base.push_data = nv50_sifc_linear_u8; 313 nv50->base.push_cb = nv50_cb_push; 314 315 nv50->screen = screen; 316 pipe->screen = pscreen; 317 pipe->priv = priv; 318 319 pipe->destroy = nv50_destroy; 320 321 pipe->draw_vbo = nv50_draw_vbo; 322 pipe->clear = nv50_clear; 323 pipe->launch_grid = nv50_launch_grid; 324 325 pipe->flush = nv50_flush; 326 pipe->texture_barrier = nv50_texture_barrier; 327 pipe->memory_barrier = nv50_memory_barrier; 328 pipe->get_sample_position = nv50_context_get_sample_position; 329 pipe->emit_string_marker = nv50_emit_string_marker; 330 331 if (!screen->cur_ctx) { 332 /* Restore the last context's state here, normally handled during 333 * context switch 334 */ 335 nv50->state = screen->save_state; 336 screen->cur_ctx = nv50; 337 nouveau_pushbuf_bufctx(screen->base.pushbuf, nv50->bufctx); 338 } 339 nv50->base.pushbuf->kick_notify = nv50_default_kick_notify; 340 341 nouveau_context_init(&nv50->base); 342 nv50_init_query_functions(nv50); 343 nv50_init_surface_functions(nv50); 344 nv50_init_state_functions(nv50); 345 nv50_init_resource_functions(pipe); 346 347 nv50->base.invalidate_resource_storage = nv50_invalidate_resource_storage; 348 349 if (screen->base.device->chipset < 0x84 || 350 debug_get_bool_option("NOUVEAU_PMPEG", false)) { 351 /* PMPEG */ 352 nouveau_context_init_vdec(&nv50->base); 353 } else if (screen->base.device->chipset < 0x98 || 354 screen->base.device->chipset == 0xa0) { 355 /* VP2 */ 356 pipe->create_video_codec = nv84_create_decoder; 357 pipe->create_video_buffer = nv84_video_buffer_create; 358 } else { 359 /* VP3/4 */ 360 pipe->create_video_codec = nv98_create_decoder; 361 pipe->create_video_buffer = nv98_video_buffer_create; 362 } 363 364 flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_RD; 365 366 BCTX_REFN_bo(nv50->bufctx_3d, 3D_SCREEN, flags, screen->code); 367 BCTX_REFN_bo(nv50->bufctx_3d, 3D_SCREEN, flags, screen->uniforms); 368 BCTX_REFN_bo(nv50->bufctx_3d, 3D_SCREEN, flags, screen->txc); 369 BCTX_REFN_bo(nv50->bufctx_3d, 3D_SCREEN, flags, screen->stack_bo); 370 if (screen->compute) { 371 BCTX_REFN_bo(nv50->bufctx_cp, CP_SCREEN, flags, screen->code); 372 BCTX_REFN_bo(nv50->bufctx_cp, CP_SCREEN, flags, screen->txc); 373 BCTX_REFN_bo(nv50->bufctx_cp, CP_SCREEN, flags, screen->stack_bo); 374 } 375 376 flags = NOUVEAU_BO_GART | NOUVEAU_BO_WR; 377 378 BCTX_REFN_bo(nv50->bufctx_3d, 3D_SCREEN, flags, screen->fence.bo); 379 BCTX_REFN_bo(nv50->bufctx, FENCE, flags, screen->fence.bo); 380 if (screen->compute) 381 BCTX_REFN_bo(nv50->bufctx_cp, CP_SCREEN, flags, screen->fence.bo); 382 383 nv50->base.scratch.bo_size = 2 << 20; 384 385 util_dynarray_init(&nv50->global_residents); 386 387 return pipe; 388 389out_err: 390 if (nv50->bufctx_3d) 391 nouveau_bufctx_del(&nv50->bufctx_3d); 392 if (nv50->bufctx_cp) 393 nouveau_bufctx_del(&nv50->bufctx_cp); 394 if (nv50->bufctx) 395 nouveau_bufctx_del(&nv50->bufctx); 396 FREE(nv50->blit); 397 FREE(nv50); 398 return NULL; 399} 400 401void 402nv50_bufctx_fence(struct nouveau_bufctx *bufctx, bool on_flush) 403{ 404 struct nouveau_list *list = on_flush ? &bufctx->current : &bufctx->pending; 405 struct nouveau_list *it; 406 407 for (it = list->next; it != list; it = it->next) { 408 struct nouveau_bufref *ref = (struct nouveau_bufref *)it; 409 struct nv04_resource *res = ref->priv; 410 if (res) 411 nv50_resource_validate(res, (unsigned)ref->priv_data); 412 } 413} 414 415static void 416nv50_context_get_sample_position(struct pipe_context *pipe, 417 unsigned sample_count, unsigned sample_index, 418 float *xy) 419{ 420 static const uint8_t ms1[1][2] = { { 0x8, 0x8 } }; 421 static const uint8_t ms2[2][2] = { 422 { 0x4, 0x4 }, { 0xc, 0xc } }; /* surface coords (0,0), (1,0) */ 423 static const uint8_t ms4[4][2] = { 424 { 0x6, 0x2 }, { 0xe, 0x6 }, /* (0,0), (1,0) */ 425 { 0x2, 0xa }, { 0xa, 0xe } }; /* (0,1), (1,1) */ 426 static const uint8_t ms8[8][2] = { 427 { 0x1, 0x7 }, { 0x5, 0x3 }, /* (0,0), (1,0) */ 428 { 0x3, 0xd }, { 0x7, 0xb }, /* (0,1), (1,1) */ 429 { 0x9, 0x5 }, { 0xf, 0x1 }, /* (2,0), (3,0) */ 430 { 0xb, 0xf }, { 0xd, 0x9 } }; /* (2,1), (3,1) */ 431#if 0 432 /* NOTE: there are alternative modes for MS2 and MS8, currently not used */ 433 static const uint8_t ms8_alt[8][2] = { 434 { 0x9, 0x5 }, { 0x7, 0xb }, /* (2,0), (1,1) */ 435 { 0xd, 0x9 }, { 0x5, 0x3 }, /* (3,1), (1,0) */ 436 { 0x3, 0xd }, { 0x1, 0x7 }, /* (0,1), (0,0) */ 437 { 0xb, 0xf }, { 0xf, 0x1 } }; /* (2,1), (3,0) */ 438#endif 439 440 const uint8_t (*ptr)[2]; 441 442 switch (sample_count) { 443 case 0: 444 case 1: ptr = ms1; break; 445 case 2: ptr = ms2; break; 446 case 4: ptr = ms4; break; 447 case 8: ptr = ms8; break; 448 default: 449 assert(0); 450 return; /* bad sample count -> undefined locations */ 451 } 452 xy[0] = ptr[sample_index][0] * 0.0625f; 453 xy[1] = ptr[sample_index][1] * 0.0625f; 454} 455