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