nv50_screen.c revision 1448d2f252efc1ab8d3175c7fd9701dfe3079577
1/* 2 * Copyright 2008 Ben Skeggs 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 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 * SOFTWARE. 21 */ 22 23#include "pipe/p_screen.h" 24 25#include "nv50_context.h" 26#include "nv50_screen.h" 27 28#include "nouveau/nouveau_stateobj.h" 29 30static boolean 31nv50_screen_is_format_supported(struct pipe_screen *pscreen, 32 enum pipe_format format, 33 enum pipe_texture_target target, 34 unsigned tex_usage, unsigned geom_flags) 35{ 36 if (tex_usage & PIPE_TEXTURE_USAGE_RENDER_TARGET) { 37 switch (format) { 38 case PIPE_FORMAT_X8R8G8B8_UNORM: 39 case PIPE_FORMAT_A8R8G8B8_UNORM: 40 case PIPE_FORMAT_R5G6B5_UNORM: 41 case PIPE_FORMAT_R16G16B16A16_SNORM: 42 case PIPE_FORMAT_R16G16B16A16_UNORM: 43 case PIPE_FORMAT_R32G32B32A32_FLOAT: 44 case PIPE_FORMAT_R16G16_SNORM: 45 case PIPE_FORMAT_R16G16_UNORM: 46 return TRUE; 47 default: 48 break; 49 } 50 } else 51 if (tex_usage & PIPE_TEXTURE_USAGE_DEPTH_STENCIL) { 52 switch (format) { 53 case PIPE_FORMAT_Z32_FLOAT: 54 case PIPE_FORMAT_Z24S8_UNORM: 55 case PIPE_FORMAT_X8Z24_UNORM: 56 case PIPE_FORMAT_S8Z24_UNORM: 57 return TRUE; 58 default: 59 break; 60 } 61 } else { 62 switch (format) { 63 case PIPE_FORMAT_A8R8G8B8_UNORM: 64 case PIPE_FORMAT_X8R8G8B8_UNORM: 65 case PIPE_FORMAT_A8R8G8B8_SRGB: 66 case PIPE_FORMAT_X8R8G8B8_SRGB: 67 case PIPE_FORMAT_A1R5G5B5_UNORM: 68 case PIPE_FORMAT_A4R4G4B4_UNORM: 69 case PIPE_FORMAT_R5G6B5_UNORM: 70 case PIPE_FORMAT_L8_UNORM: 71 case PIPE_FORMAT_A8_UNORM: 72 case PIPE_FORMAT_I8_UNORM: 73 case PIPE_FORMAT_A8L8_UNORM: 74 case PIPE_FORMAT_DXT1_RGB: 75 case PIPE_FORMAT_DXT1_RGBA: 76 case PIPE_FORMAT_DXT3_RGBA: 77 case PIPE_FORMAT_DXT5_RGBA: 78 case PIPE_FORMAT_Z24S8_UNORM: 79 case PIPE_FORMAT_S8Z24_UNORM: 80 case PIPE_FORMAT_Z32_FLOAT: 81 case PIPE_FORMAT_R16G16B16A16_SNORM: 82 case PIPE_FORMAT_R16G16B16A16_UNORM: 83 case PIPE_FORMAT_R32G32B32A32_FLOAT: 84 case PIPE_FORMAT_R16G16_SNORM: 85 case PIPE_FORMAT_R16G16_UNORM: 86 return TRUE; 87 default: 88 break; 89 } 90 } 91 92 return FALSE; 93} 94 95static int 96nv50_screen_get_param(struct pipe_screen *pscreen, int param) 97{ 98 switch (param) { 99 case PIPE_CAP_MAX_TEXTURE_IMAGE_UNITS: 100 return 32; 101 case PIPE_CAP_MAX_VERTEX_TEXTURE_UNITS: 102 return 32; 103 case PIPE_CAP_MAX_COMBINED_SAMPLERS: 104 return 64; 105 case PIPE_CAP_NPOT_TEXTURES: 106 return 1; 107 case PIPE_CAP_TWO_SIDED_STENCIL: 108 return 1; 109 case PIPE_CAP_GLSL: 110 return 0; 111 case PIPE_CAP_ANISOTROPIC_FILTER: 112 return 1; 113 case PIPE_CAP_POINT_SPRITE: 114 return 1; 115 case PIPE_CAP_MAX_RENDER_TARGETS: 116 return 8; 117 case PIPE_CAP_OCCLUSION_QUERY: 118 return 1; 119 case PIPE_CAP_TEXTURE_SHADOW_MAP: 120 return 1; 121 case PIPE_CAP_MAX_TEXTURE_2D_LEVELS: 122 return 13; 123 case PIPE_CAP_MAX_TEXTURE_3D_LEVELS: 124 return 10; 125 case PIPE_CAP_MAX_TEXTURE_CUBE_LEVELS: 126 return 13; 127 case PIPE_CAP_TEXTURE_MIRROR_CLAMP: 128 case PIPE_CAP_TEXTURE_MIRROR_REPEAT: 129 return 1; 130 case PIPE_CAP_TGSI_CONT_SUPPORTED: 131 return 1; 132 case PIPE_CAP_BLEND_EQUATION_SEPARATE: 133 return 1; 134 case NOUVEAU_CAP_HW_VTXBUF: 135 return 1; 136 case NOUVEAU_CAP_HW_IDXBUF: 137 return 0; 138 default: 139 NOUVEAU_ERR("Unknown PIPE_CAP %d\n", param); 140 return 0; 141 } 142} 143 144static float 145nv50_screen_get_paramf(struct pipe_screen *pscreen, int param) 146{ 147 switch (param) { 148 case PIPE_CAP_MAX_LINE_WIDTH: 149 case PIPE_CAP_MAX_LINE_WIDTH_AA: 150 return 10.0; 151 case PIPE_CAP_MAX_POINT_WIDTH: 152 case PIPE_CAP_MAX_POINT_WIDTH_AA: 153 return 64.0; 154 case PIPE_CAP_MAX_TEXTURE_ANISOTROPY: 155 return 16.0; 156 case PIPE_CAP_MAX_TEXTURE_LOD_BIAS: 157 return 4.0; 158 default: 159 NOUVEAU_ERR("Unknown PIPE_CAP %d\n", param); 160 return 0.0; 161 } 162} 163 164static void 165nv50_screen_destroy(struct pipe_screen *pscreen) 166{ 167 struct nv50_screen *screen = nv50_screen(pscreen); 168 unsigned i; 169 170 for (i = 0; i < 3; i++) { 171 if (screen->constbuf_parm[i]) 172 nouveau_bo_ref(NULL, &screen->constbuf_parm[i]); 173 } 174 175 if (screen->constbuf_misc[0]) 176 nouveau_bo_ref(NULL, &screen->constbuf_misc[0]); 177 if (screen->tic) 178 nouveau_bo_ref(NULL, &screen->tic); 179 if (screen->tsc) 180 nouveau_bo_ref(NULL, &screen->tsc); 181 if (screen->static_init) 182 so_ref(NULL, &screen->static_init); 183 184 nouveau_notifier_free(&screen->sync); 185 nouveau_grobj_free(&screen->tesla); 186 nouveau_grobj_free(&screen->eng2d); 187 nouveau_grobj_free(&screen->m2mf); 188 nouveau_screen_fini(&screen->base); 189 FREE(screen); 190} 191 192static int 193nv50_pre_pipebuffer_map(struct pipe_screen *pscreen, struct pipe_buffer *pb, 194 unsigned usage) 195{ 196 struct nv50_screen *screen = nv50_screen(pscreen); 197 struct nv50_context *ctx = screen->cur_ctx; 198 199 if (!(pb->usage & PIPE_BUFFER_USAGE_VERTEX)) 200 return 0; 201 202 /* Our vtxbuf got mapped, it can no longer be considered part of current 203 * state, remove it to avoid emitting reloc markers. 204 */ 205 if (ctx && ctx->state.vtxbuf && so_bo_is_reloc(ctx->state.vtxbuf, 206 nouveau_bo(pb))) { 207 so_ref(NULL, &ctx->state.vtxbuf); 208 ctx->dirty |= NV50_NEW_ARRAYS; 209 } 210 211 return 0; 212} 213 214struct pipe_screen * 215nv50_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev) 216{ 217 struct nv50_screen *screen = CALLOC_STRUCT(nv50_screen); 218 struct nouveau_channel *chan; 219 struct pipe_screen *pscreen; 220 struct nouveau_stateobj *so; 221 unsigned chipset = dev->chipset; 222 unsigned tesla_class = 0; 223 int ret, i; 224 225 if (!screen) 226 return NULL; 227 pscreen = &screen->base.base; 228 229 ret = nouveau_screen_init(&screen->base, dev); 230 if (ret) { 231 nv50_screen_destroy(pscreen); 232 return NULL; 233 } 234 chan = screen->base.channel; 235 236 pscreen->winsys = ws; 237 pscreen->destroy = nv50_screen_destroy; 238 pscreen->get_param = nv50_screen_get_param; 239 pscreen->get_paramf = nv50_screen_get_paramf; 240 pscreen->is_format_supported = nv50_screen_is_format_supported; 241 screen->base.pre_pipebuffer_map_callback = nv50_pre_pipebuffer_map; 242 243 nv50_screen_init_miptree_functions(pscreen); 244 nv50_transfer_init_screen_functions(pscreen); 245 246 /* DMA engine object */ 247 ret = nouveau_grobj_alloc(chan, 0xbeef5039, 248 NV50_MEMORY_TO_MEMORY_FORMAT, &screen->m2mf); 249 if (ret) { 250 NOUVEAU_ERR("Error creating M2MF object: %d\n", ret); 251 nv50_screen_destroy(pscreen); 252 return NULL; 253 } 254 255 /* 2D object */ 256 ret = nouveau_grobj_alloc(chan, 0xbeef502d, NV50_2D, &screen->eng2d); 257 if (ret) { 258 NOUVEAU_ERR("Error creating 2D object: %d\n", ret); 259 nv50_screen_destroy(pscreen); 260 return NULL; 261 } 262 263 /* 3D object */ 264 switch (chipset & 0xf0) { 265 case 0x50: 266 tesla_class = NV50TCL; 267 break; 268 case 0x80: 269 case 0x90: 270 tesla_class = NV84TCL; 271 break; 272 case 0xa0: 273 switch (chipset) { 274 case 0xa0: 275 case 0xaa: 276 case 0xac: 277 tesla_class = NVA0TCL; 278 break; 279 default: 280 tesla_class = NVA8TCL; 281 break; 282 } 283 break; 284 default: 285 NOUVEAU_ERR("Not a known NV50 chipset: NV%02x\n", chipset); 286 nv50_screen_destroy(pscreen); 287 return NULL; 288 } 289 290 ret = nouveau_grobj_alloc(chan, 0xbeef5097, tesla_class, 291 &screen->tesla); 292 if (ret) { 293 NOUVEAU_ERR("Error creating 3D object: %d\n", ret); 294 nv50_screen_destroy(pscreen); 295 return NULL; 296 } 297 298 /* Sync notifier */ 299 ret = nouveau_notifier_alloc(chan, 0xbeef0301, 1, &screen->sync); 300 if (ret) { 301 NOUVEAU_ERR("Error creating notifier object: %d\n", ret); 302 nv50_screen_destroy(pscreen); 303 return NULL; 304 } 305 306 /* Static M2MF init */ 307 so = so_new(1, 3, 0); 308 so_method(so, screen->m2mf, NV04_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 3); 309 so_data (so, screen->sync->handle); 310 so_data (so, chan->vram->handle); 311 so_data (so, chan->vram->handle); 312 so_emit(chan, so); 313 so_ref (NULL, &so); 314 315 /* Static 2D init */ 316 so = so_new(4, 7, 0); 317 so_method(so, screen->eng2d, NV50_2D_DMA_NOTIFY, 4); 318 so_data (so, screen->sync->handle); 319 so_data (so, chan->vram->handle); 320 so_data (so, chan->vram->handle); 321 so_data (so, chan->vram->handle); 322 so_method(so, screen->eng2d, NV50_2D_OPERATION, 1); 323 so_data (so, NV50_2D_OPERATION_SRCCOPY); 324 so_method(so, screen->eng2d, NV50_2D_CLIP_ENABLE, 1); 325 so_data (so, 0); 326 so_method(so, screen->eng2d, 0x0888, 1); 327 so_data (so, 1); 328 so_emit(chan, so); 329 so_ref(NULL, &so); 330 331 /* Static tesla init */ 332 so = so_new(47, 95, 24); 333 334 so_method(so, screen->tesla, NV50TCL_COND_MODE, 1); 335 so_data (so, NV50TCL_COND_MODE_ALWAYS); 336 so_method(so, screen->tesla, NV50TCL_DMA_NOTIFY, 1); 337 so_data (so, screen->sync->handle); 338 so_method(so, screen->tesla, NV50TCL_DMA_ZETA, 11); 339 for (i = 0; i < 11; i++) 340 so_data(so, chan->vram->handle); 341 so_method(so, screen->tesla, NV50TCL_DMA_COLOR(0), 342 NV50TCL_DMA_COLOR__SIZE); 343 for (i = 0; i < NV50TCL_DMA_COLOR__SIZE; i++) 344 so_data(so, chan->vram->handle); 345 so_method(so, screen->tesla, NV50TCL_RT_CONTROL, 1); 346 so_data (so, 1); 347 348 /* activate all 32 lanes (threads) in a warp */ 349 so_method(so, screen->tesla, NV50TCL_WARP_HALVES, 1); 350 so_data (so, 0x2); 351 so_method(so, screen->tesla, 0x1400, 1); 352 so_data (so, 0xf); 353 354 /* max TIC (bits 4:8) & TSC (ignored) bindings, per program type */ 355 for (i = 0; i < 3; ++i) { 356 so_method(so, screen->tesla, NV50TCL_TEX_LIMITS(i), 1); 357 so_data (so, 0x54); 358 } 359 360 /* origin is top left (set to 1 for bottom left) */ 361 so_method(so, screen->tesla, NV50TCL_Y_ORIGIN_BOTTOM, 1); 362 so_data (so, 0); 363 so_method(so, screen->tesla, NV50TCL_VP_REG_ALLOC_RESULT, 1); 364 so_data (so, 8); 365 366 /* constant buffers for immediates and VP/FP parameters */ 367 ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 0, (32 * 4) * 4, 368 &screen->constbuf_misc[0]); 369 if (ret) { 370 nv50_screen_destroy(pscreen); 371 return NULL; 372 } 373 374 for (i = 0; i < 3; i++) { 375 ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 0, (256 * 4) * 4, 376 &screen->constbuf_parm[i]); 377 if (ret) { 378 nv50_screen_destroy(pscreen); 379 return NULL; 380 } 381 } 382 383 if (nouveau_resource_init(&screen->immd_heap[0], 0, 128) || 384 nouveau_resource_init(&screen->parm_heap[0], 0, 512) || 385 nouveau_resource_init(&screen->parm_heap[1], 0, 512)) 386 { 387 NOUVEAU_ERR("Error initialising constant buffers.\n"); 388 nv50_screen_destroy(pscreen); 389 return NULL; 390 } 391 392 /* 393 // map constant buffers: 394 // B = buffer ID (maybe more than 1 byte) 395 // N = CB index used in shader instruction 396 // P = program type (0 = VP, 2 = GP, 3 = FP) 397 so_method(so, screen->tesla, NV50TCL_SET_PROGRAM_CB, 1); 398 so_data (so, 0x000BBNP1); 399 */ 400 401 so_method(so, screen->tesla, NV50TCL_CB_DEF_ADDRESS_HIGH, 3); 402 so_reloc (so, screen->constbuf_misc[0], 0, NOUVEAU_BO_VRAM | 403 NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0); 404 so_reloc (so, screen->constbuf_misc[0], 0, NOUVEAU_BO_VRAM | 405 NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0); 406 so_data (so, (NV50_CB_PMISC << 16) | 0x00000200); 407 so_method(so, screen->tesla, NV50TCL_SET_PROGRAM_CB, 1); 408 so_data (so, 0x00000001 | (NV50_CB_PMISC << 12)); 409 so_method(so, screen->tesla, NV50TCL_SET_PROGRAM_CB, 1); 410 so_data (so, 0x00000021 | (NV50_CB_PMISC << 12)); 411 so_method(so, screen->tesla, NV50TCL_SET_PROGRAM_CB, 1); 412 so_data (so, 0x00000031 | (NV50_CB_PMISC << 12)); 413 414 /* bind auxiliary constbuf to immediate data bo */ 415 so_method(so, screen->tesla, NV50TCL_CB_DEF_ADDRESS_HIGH, 3); 416 so_reloc (so, screen->constbuf_misc[0], (128 * 4) * 4, 417 NOUVEAU_BO_VRAM | NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0); 418 so_reloc (so, screen->constbuf_misc[0], (128 * 4) * 4, 419 NOUVEAU_BO_VRAM | NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0); 420 so_data (so, (NV50_CB_AUX << 16) | 0x00000200); 421 so_method(so, screen->tesla, NV50TCL_SET_PROGRAM_CB, 1); 422 so_data (so, 0x00000201 | (NV50_CB_AUX << 12)); 423 so_method(so, screen->tesla, NV50TCL_SET_PROGRAM_CB, 1); 424 so_data (so, 0x00000221 | (NV50_CB_AUX << 12)); 425 426 so_method(so, screen->tesla, NV50TCL_CB_DEF_ADDRESS_HIGH, 3); 427 so_reloc (so, screen->constbuf_parm[PIPE_SHADER_VERTEX], 0, 428 NOUVEAU_BO_VRAM | NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0); 429 so_reloc (so, screen->constbuf_parm[PIPE_SHADER_VERTEX], 0, 430 NOUVEAU_BO_VRAM | NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0); 431 so_data (so, (NV50_CB_PVP << 16) | 0x00000800); 432 so_method(so, screen->tesla, NV50TCL_SET_PROGRAM_CB, 1); 433 so_data (so, 0x00000101 | (NV50_CB_PVP << 12)); 434 435 so_method(so, screen->tesla, NV50TCL_CB_DEF_ADDRESS_HIGH, 3); 436 so_reloc (so, screen->constbuf_parm[PIPE_SHADER_GEOMETRY], 0, 437 NOUVEAU_BO_VRAM | NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0); 438 so_reloc (so, screen->constbuf_parm[PIPE_SHADER_GEOMETRY], 0, 439 NOUVEAU_BO_VRAM | NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0); 440 so_data (so, (NV50_CB_PGP << 16) | 0x00000800); 441 so_method(so, screen->tesla, NV50TCL_SET_PROGRAM_CB, 1); 442 so_data (so, 0x00000121 | (NV50_CB_PGP << 12)); 443 444 so_method(so, screen->tesla, NV50TCL_CB_DEF_ADDRESS_HIGH, 3); 445 so_reloc (so, screen->constbuf_parm[PIPE_SHADER_FRAGMENT], 0, 446 NOUVEAU_BO_VRAM | NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0); 447 so_reloc (so, screen->constbuf_parm[PIPE_SHADER_FRAGMENT], 0, 448 NOUVEAU_BO_VRAM | NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0); 449 so_data (so, (NV50_CB_PFP << 16) | 0x00000800); 450 so_method(so, screen->tesla, NV50TCL_SET_PROGRAM_CB, 1); 451 so_data (so, 0x00000131 | (NV50_CB_PFP << 12)); 452 453 ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 0, PIPE_SHADER_TYPES*32*32, 454 &screen->tic); 455 if (ret) { 456 nv50_screen_destroy(pscreen); 457 return NULL; 458 } 459 460 so_method(so, screen->tesla, NV50TCL_TIC_ADDRESS_HIGH, 3); 461 so_reloc (so, screen->tic, 0, NOUVEAU_BO_VRAM | 462 NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0); 463 so_reloc (so, screen->tic, 0, NOUVEAU_BO_VRAM | 464 NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0); 465 so_data (so, PIPE_SHADER_TYPES * 32 - 1); 466 467 ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 0, PIPE_SHADER_TYPES*32*32, 468 &screen->tsc); 469 if (ret) { 470 nv50_screen_destroy(pscreen); 471 return NULL; 472 } 473 474 so_method(so, screen->tesla, NV50TCL_TSC_ADDRESS_HIGH, 3); 475 so_reloc (so, screen->tsc, 0, NOUVEAU_BO_VRAM | 476 NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0); 477 so_reloc (so, screen->tsc, 0, NOUVEAU_BO_VRAM | 478 NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0); 479 so_data (so, 0x00000000); /* ignored if TSC_LINKED (0x1234) = 1 */ 480 481 482 /* Vertex array limits - max them out */ 483 for (i = 0; i < 16; i++) { 484 so_method(so, screen->tesla, NV50TCL_VERTEX_ARRAY_LIMIT_HIGH(i), 2); 485 so_data (so, 0x000000ff); 486 so_data (so, 0xffffffff); 487 } 488 489 so_method(so, screen->tesla, NV50TCL_DEPTH_RANGE_NEAR(0), 2); 490 so_data (so, fui(0.0)); 491 so_data (so, fui(1.0)); 492 493 /* no dynamic combination of TIC & TSC entries => only BIND_TIC used */ 494 so_method(so, screen->tesla, NV50TCL_LINKED_TSC, 1); 495 so_data (so, 1); 496 497 /* activate first scissor rectangle */ 498 so_method(so, screen->tesla, NV50TCL_SCISSOR_ENABLE(0), 1); 499 so_data (so, 1); 500 501 so_method(so, screen->tesla, NV50TCL_EDGEFLAG_ENABLE, 1); 502 so_data (so, 1); /* default edgeflag to TRUE */ 503 504 so_emit(chan, so); 505 so_ref (so, &screen->static_init); 506 so_ref (NULL, &so); 507 nouveau_pushbuf_flush(chan, 0); 508 509 return pscreen; 510} 511 512