nv50_screen.c revision 01670ca8073b57029625873b5c8374fb8716e1eb
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_A8R8G8B8_UNORM: 39 case PIPE_FORMAT_R5G6B5_UNORM: 40 return TRUE; 41 default: 42 break; 43 } 44 } else 45 if (tex_usage & PIPE_TEXTURE_USAGE_DEPTH_STENCIL) { 46 switch (format) { 47 case PIPE_FORMAT_Z32_FLOAT: 48 case PIPE_FORMAT_Z24S8_UNORM: 49 case PIPE_FORMAT_X8Z24_UNORM: 50 case PIPE_FORMAT_S8Z24_UNORM: 51 return TRUE; 52 default: 53 break; 54 } 55 } else { 56 switch (format) { 57 case PIPE_FORMAT_A8R8G8B8_UNORM: 58 case PIPE_FORMAT_A1R5G5B5_UNORM: 59 case PIPE_FORMAT_A4R4G4B4_UNORM: 60 case PIPE_FORMAT_R5G6B5_UNORM: 61 case PIPE_FORMAT_L8_UNORM: 62 case PIPE_FORMAT_A8_UNORM: 63 case PIPE_FORMAT_I8_UNORM: 64 case PIPE_FORMAT_A8L8_UNORM: 65 case PIPE_FORMAT_DXT1_RGB: 66 case PIPE_FORMAT_DXT1_RGBA: 67 case PIPE_FORMAT_DXT3_RGBA: 68 case PIPE_FORMAT_DXT5_RGBA: 69 return TRUE; 70 default: 71 break; 72 } 73 } 74 75 return FALSE; 76} 77 78static int 79nv50_screen_get_param(struct pipe_screen *pscreen, int param) 80{ 81 switch (param) { 82 case PIPE_CAP_MAX_TEXTURE_IMAGE_UNITS: 83 return 32; 84 case PIPE_CAP_NPOT_TEXTURES: 85 return 1; 86 case PIPE_CAP_TWO_SIDED_STENCIL: 87 return 1; 88 case PIPE_CAP_GLSL: 89 return 0; 90 case PIPE_CAP_S3TC: 91 return 1; 92 case PIPE_CAP_ANISOTROPIC_FILTER: 93 return 1; 94 case PIPE_CAP_POINT_SPRITE: 95 return 1; 96 case PIPE_CAP_MAX_RENDER_TARGETS: 97 return 8; 98 case PIPE_CAP_OCCLUSION_QUERY: 99 return 1; 100 case PIPE_CAP_TEXTURE_SHADOW_MAP: 101 return 1; 102 case PIPE_CAP_MAX_TEXTURE_2D_LEVELS: 103 return 13; 104 case PIPE_CAP_MAX_TEXTURE_3D_LEVELS: 105 return 10; 106 case PIPE_CAP_MAX_TEXTURE_CUBE_LEVELS: 107 return 13; 108 case PIPE_CAP_TEXTURE_MIRROR_CLAMP: 109 case PIPE_CAP_TEXTURE_MIRROR_REPEAT: 110 return 1; 111 case PIPE_CAP_MAX_VERTEX_TEXTURE_UNITS: 112 return 0; 113 case PIPE_CAP_TGSI_CONT_SUPPORTED: 114 return 0; 115 case PIPE_CAP_BLEND_EQUATION_SEPARATE: 116 return 1; 117 case NOUVEAU_CAP_HW_VTXBUF: 118 return 1; 119 case NOUVEAU_CAP_HW_IDXBUF: 120 return 0; 121 default: 122 NOUVEAU_ERR("Unknown PIPE_CAP %d\n", param); 123 return 0; 124 } 125} 126 127static float 128nv50_screen_get_paramf(struct pipe_screen *pscreen, int param) 129{ 130 switch (param) { 131 case PIPE_CAP_MAX_LINE_WIDTH: 132 case PIPE_CAP_MAX_LINE_WIDTH_AA: 133 return 10.0; 134 case PIPE_CAP_MAX_POINT_WIDTH: 135 case PIPE_CAP_MAX_POINT_WIDTH_AA: 136 return 64.0; 137 case PIPE_CAP_MAX_TEXTURE_ANISOTROPY: 138 return 16.0; 139 case PIPE_CAP_MAX_TEXTURE_LOD_BIAS: 140 return 4.0; 141 default: 142 NOUVEAU_ERR("Unknown PIPE_CAP %d\n", param); 143 return 0.0; 144 } 145} 146 147static void 148nv50_screen_destroy(struct pipe_screen *pscreen) 149{ 150 struct nv50_screen *screen = nv50_screen(pscreen); 151 152 nouveau_notifier_free(&screen->sync); 153 nouveau_grobj_free(&screen->tesla); 154 nouveau_grobj_free(&screen->eng2d); 155 nouveau_grobj_free(&screen->m2mf); 156 nouveau_screen_fini(&screen->base); 157 FREE(screen); 158} 159 160struct pipe_screen * 161nv50_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev) 162{ 163 struct nv50_screen *screen = CALLOC_STRUCT(nv50_screen); 164 struct nouveau_channel *chan; 165 struct pipe_screen *pscreen; 166 struct nouveau_stateobj *so; 167 unsigned chipset = dev->chipset; 168 unsigned tesla_class = 0; 169 int ret, i; 170 171 if (!screen) 172 return NULL; 173 pscreen = &screen->base.base; 174 175 ret = nouveau_screen_init(&screen->base, dev); 176 if (ret) { 177 nv50_screen_destroy(pscreen); 178 return NULL; 179 } 180 chan = screen->base.channel; 181 182 pscreen->winsys = ws; 183 pscreen->destroy = nv50_screen_destroy; 184 pscreen->get_param = nv50_screen_get_param; 185 pscreen->get_paramf = nv50_screen_get_paramf; 186 pscreen->is_format_supported = nv50_screen_is_format_supported; 187 188 nv50_screen_init_miptree_functions(pscreen); 189 nv50_transfer_init_screen_functions(pscreen); 190 191 /* DMA engine object */ 192 ret = nouveau_grobj_alloc(chan, 0xbeef5039, 193 NV50_MEMORY_TO_MEMORY_FORMAT, &screen->m2mf); 194 if (ret) { 195 NOUVEAU_ERR("Error creating M2MF object: %d\n", ret); 196 nv50_screen_destroy(pscreen); 197 return NULL; 198 } 199 BIND_RING(chan, screen->m2mf, 1); 200 201 /* 2D object */ 202 ret = nouveau_grobj_alloc(chan, 0xbeef502d, NV50_2D, &screen->eng2d); 203 if (ret) { 204 NOUVEAU_ERR("Error creating 2D object: %d\n", ret); 205 nv50_screen_destroy(pscreen); 206 return NULL; 207 } 208 BIND_RING(chan, screen->eng2d, 2); 209 210 /* 3D object */ 211 switch (chipset & 0xf0) { 212 case 0x50: 213 tesla_class = NV50TCL; 214 break; 215 case 0x80: 216 case 0x90: 217 /* this stupid name should be corrected. */ 218 tesla_class = NV54TCL; 219 break; 220 case 0xa0: 221 tesla_class = NVA0TCL; 222 break; 223 default: 224 NOUVEAU_ERR("Not a known NV50 chipset: NV%02x\n", chipset); 225 nv50_screen_destroy(pscreen); 226 return NULL; 227 } 228 229 if (tesla_class == 0) { 230 NOUVEAU_ERR("Unknown G8x chipset: NV%02x\n", chipset); 231 nv50_screen_destroy(pscreen); 232 return NULL; 233 } 234 235 ret = nouveau_grobj_alloc(chan, 0xbeef5097, tesla_class, 236 &screen->tesla); 237 if (ret) { 238 NOUVEAU_ERR("Error creating 3D object: %d\n", ret); 239 nv50_screen_destroy(pscreen); 240 return NULL; 241 } 242 BIND_RING(chan, screen->tesla, 3); 243 244 /* Sync notifier */ 245 ret = nouveau_notifier_alloc(chan, 0xbeef0301, 1, &screen->sync); 246 if (ret) { 247 NOUVEAU_ERR("Error creating notifier object: %d\n", ret); 248 nv50_screen_destroy(pscreen); 249 return NULL; 250 } 251 252 /* Static M2MF init */ 253 so = so_new(32, 0); 254 so_method(so, screen->m2mf, NV04_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 3); 255 so_data (so, screen->sync->handle); 256 so_data (so, chan->vram->handle); 257 so_data (so, chan->vram->handle); 258 so_emit(chan, so); 259 so_ref (NULL, &so); 260 261 /* Static 2D init */ 262 so = so_new(64, 0); 263 so_method(so, screen->eng2d, NV50_2D_DMA_NOTIFY, 4); 264 so_data (so, screen->sync->handle); 265 so_data (so, chan->vram->handle); 266 so_data (so, chan->vram->handle); 267 so_data (so, chan->vram->handle); 268 so_method(so, screen->eng2d, NV50_2D_OPERATION, 1); 269 so_data (so, NV50_2D_OPERATION_SRCCOPY); 270 so_method(so, screen->eng2d, 0x0290, 1); 271 so_data (so, 0); 272 so_method(so, screen->eng2d, 0x0888, 1); 273 so_data (so, 1); 274 so_emit(chan, so); 275 so_ref(NULL, &so); 276 277 /* Static tesla init */ 278 so = so_new(256, 20); 279 280 so_method(so, screen->tesla, 0x1558, 1); 281 so_data (so, 1); 282 so_method(so, screen->tesla, NV50TCL_DMA_NOTIFY, 1); 283 so_data (so, screen->sync->handle); 284 so_method(so, screen->tesla, NV50TCL_DMA_UNK0(0), 285 NV50TCL_DMA_UNK0__SIZE); 286 for (i = 0; i < NV50TCL_DMA_UNK0__SIZE; i++) 287 so_data(so, chan->vram->handle); 288 so_method(so, screen->tesla, NV50TCL_DMA_UNK1(0), 289 NV50TCL_DMA_UNK1__SIZE); 290 for (i = 0; i < NV50TCL_DMA_UNK1__SIZE; i++) 291 so_data(so, chan->vram->handle); 292 so_method(so, screen->tesla, 0x121c, 1); 293 so_data (so, 1); 294 295 so_method(so, screen->tesla, 0x13bc, 1); 296 so_data (so, 0x54); 297 /* origin is top left (set to 1 for bottom left) */ 298 so_method(so, screen->tesla, 0x13ac, 1); 299 so_data (so, 0); 300 so_method(so, screen->tesla, NV50TCL_VP_REG_ALLOC_RESULT, 1); 301 so_data (so, 8); 302 303 /* constant buffers for immediates and VP/FP parameters */ 304 ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 0, 128*4*4, 305 &screen->constbuf_misc[0]); 306 if (ret) { 307 nv50_screen_destroy(pscreen); 308 return NULL; 309 } 310 311 for (i = 0; i < 2; i++) { 312 ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 0, 128*4*4, 313 &screen->constbuf_parm[i]); 314 if (ret) { 315 nv50_screen_destroy(pscreen); 316 return NULL; 317 } 318 } 319 320 if (nouveau_resource_init(&screen->immd_heap[0], 0, 128) || 321 nouveau_resource_init(&screen->parm_heap[0], 0, 128) || 322 nouveau_resource_init(&screen->parm_heap[1], 0, 128)) 323 { 324 NOUVEAU_ERR("Error initialising constant buffers.\n"); 325 nv50_screen_destroy(pscreen); 326 return NULL; 327 } 328 329 /* 330 // map constant buffers: 331 // B = buffer ID (maybe more than 1 byte) 332 // N = CB index used in shader instruction 333 // P = program type (0 = VP, 2 = GP, 3 = FP) 334 so_method(so, screen->tesla, 0x1694, 1); 335 so_data (so, 0x000BBNP1); 336 */ 337 338 so_method(so, screen->tesla, NV50TCL_CB_DEF_ADDRESS_HIGH, 3); 339 so_reloc (so, screen->constbuf_misc[0], 0, NOUVEAU_BO_VRAM | 340 NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0); 341 so_reloc (so, screen->constbuf_misc[0], 0, NOUVEAU_BO_VRAM | 342 NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0); 343 so_data (so, (NV50_CB_PMISC << 16) | 0x00000800); 344 so_method(so, screen->tesla, NV50TCL_SET_PROGRAM_CB, 1); 345 so_data (so, 0x00000001 | (NV50_CB_PMISC << 12)); 346 so_method(so, screen->tesla, NV50TCL_SET_PROGRAM_CB, 1); 347 so_data (so, 0x00000031 | (NV50_CB_PMISC << 12)); 348 349 so_method(so, screen->tesla, NV50TCL_CB_DEF_ADDRESS_HIGH, 3); 350 so_reloc (so, screen->constbuf_parm[0], 0, NOUVEAU_BO_VRAM | 351 NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0); 352 so_reloc (so, screen->constbuf_parm[0], 0, NOUVEAU_BO_VRAM | 353 NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0); 354 so_data (so, (NV50_CB_PVP << 16) | 0x00000800); 355 so_method(so, screen->tesla, NV50TCL_SET_PROGRAM_CB, 1); 356 so_data (so, 0x00000101 | (NV50_CB_PVP << 12)); 357 358 so_method(so, screen->tesla, NV50TCL_CB_DEF_ADDRESS_HIGH, 3); 359 so_reloc (so, screen->constbuf_parm[1], 0, NOUVEAU_BO_VRAM | 360 NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0); 361 so_reloc (so, screen->constbuf_parm[1], 0, NOUVEAU_BO_VRAM | 362 NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0); 363 so_data (so, (NV50_CB_PFP << 16) | 0x00000800); 364 so_method(so, screen->tesla, NV50TCL_SET_PROGRAM_CB, 1); 365 so_data (so, 0x00000131 | (NV50_CB_PFP << 12)); 366 367 /* Texture sampler/image unit setup - we abuse the constant buffer 368 * upload mechanism for the moment to upload data to the tex config 369 * blocks. At some point we *may* want to go the NVIDIA way of doing 370 * things? 371 */ 372 ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 0, 32*8*4, &screen->tic); 373 if (ret) { 374 nv50_screen_destroy(pscreen); 375 return NULL; 376 } 377 378 so_method(so, screen->tesla, NV50TCL_CB_DEF_ADDRESS_HIGH, 3); 379 so_reloc (so, screen->tic, 0, NOUVEAU_BO_VRAM | 380 NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0); 381 so_reloc (so, screen->tic, 0, NOUVEAU_BO_VRAM | 382 NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0); 383 so_data (so, (NV50_CB_TIC << 16) | 0x0800); 384 so_method(so, screen->tesla, NV50TCL_TIC_ADDRESS_HIGH, 3); 385 so_reloc (so, screen->tic, 0, NOUVEAU_BO_VRAM | 386 NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0); 387 so_reloc (so, screen->tic, 0, NOUVEAU_BO_VRAM | 388 NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0); 389 so_data (so, 0x00000800); 390 391 ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 0, 32*8*4, &screen->tsc); 392 if (ret) { 393 nv50_screen_destroy(pscreen); 394 return NULL; 395 } 396 397 so_method(so, screen->tesla, NV50TCL_CB_DEF_ADDRESS_HIGH, 3); 398 so_reloc (so, screen->tsc, 0, NOUVEAU_BO_VRAM | 399 NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0); 400 so_reloc (so, screen->tsc, 0, NOUVEAU_BO_VRAM | 401 NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0); 402 so_data (so, (NV50_CB_TSC << 16) | 0x0800); 403 so_method(so, screen->tesla, NV50TCL_TSC_ADDRESS_HIGH, 3); 404 so_reloc (so, screen->tsc, 0, NOUVEAU_BO_VRAM | 405 NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0); 406 so_reloc (so, screen->tsc, 0, NOUVEAU_BO_VRAM | 407 NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0); 408 so_data (so, 0x00000800); 409 410 411 /* Vertex array limits - max them out */ 412 for (i = 0; i < 16; i++) { 413 so_method(so, screen->tesla, NV50TCL_UNK1080_OFFSET_HIGH(i), 2); 414 so_data (so, 0x000000ff); 415 so_data (so, 0xffffffff); 416 } 417 418 so_method(so, screen->tesla, NV50TCL_DEPTH_RANGE_NEAR, 2); 419 so_data (so, fui(0.0)); 420 so_data (so, fui(1.0)); 421 422 so_method(so, screen->tesla, 0x1234, 1); 423 so_data (so, 1); 424 425 /* activate first scissor rectangle */ 426 so_method(so, screen->tesla, NV50TCL_SCISSOR_ENABLE, 1); 427 so_data (so, 1); 428 429 so_emit(chan, so); 430 so_ref (so, &screen->static_init); 431 so_ref (NULL, &so); 432 nouveau_pushbuf_flush(chan, 0); 433 434 return pscreen; 435} 436 437