radeon_context.c revision d450d0b0e228e5b16c04b2a1acb9ea549aa690f2
1/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_context.c,v 1.9 2003/09/24 02:43:12 dawes Exp $ */ 2/************************************************************************** 3 4Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and 5 VA Linux Systems Inc., Fremont, California. 6 7All Rights Reserved. 8 9Permission is hereby granted, free of charge, to any person obtaining 10a copy of this software and associated documentation files (the 11"Software"), to deal in the Software without restriction, including 12without limitation the rights to use, copy, modify, merge, publish, 13distribute, sublicense, and/or sell copies of the Software, and to 14permit persons to whom the Software is furnished to do so, subject to 15the following conditions: 16 17The above copyright notice and this permission notice (including the 18next paragraph) shall be included in all copies or substantial 19portions of the Software. 20 21THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 24IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE 25LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 26OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 27WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 29**************************************************************************/ 30 31/* 32 * Authors: 33 * Kevin E. Martin <martin@valinux.com> 34 * Gareth Hughes <gareth@valinux.com> 35 * Keith Whitwell <keith@tungstengraphics.com> 36 */ 37 38#include "glheader.h" 39#include "api_arrayelt.h" 40#include "context.h" 41#include "simple_list.h" 42#include "imports.h" 43#include "matrix.h" 44#include "extensions.h" 45 46#include "swrast/swrast.h" 47#include "swrast_setup/swrast_setup.h" 48#include "array_cache/acache.h" 49 50#include "tnl/tnl.h" 51#include "tnl/t_pipeline.h" 52 53#include "radeon_context.h" 54#include "radeon_ioctl.h" 55#include "radeon_state.h" 56#include "radeon_span.h" 57#include "radeon_tex.h" 58#include "radeon_swtcl.h" 59#include "radeon_tcl.h" 60#include "radeon_vtxfmt.h" 61#include "radeon_maos.h" 62 63#define DRIVER_DATE "20030328" 64 65#include "vblank.h" 66#include "utils.h" 67#include "xmlpool.h" /* for symbolic values of enum-type options */ 68#ifndef RADEON_DEBUG 69int RADEON_DEBUG = (0); 70#endif 71 72 73/* Return the width and height of the given buffer. 74 */ 75static void radeonGetBufferSize( GLframebuffer *buffer, 76 GLuint *width, GLuint *height ) 77{ 78 GET_CURRENT_CONTEXT(ctx); 79 radeonContextPtr rmesa = RADEON_CONTEXT(ctx); 80 81 LOCK_HARDWARE( rmesa ); 82 *width = rmesa->dri.drawable->w; 83 *height = rmesa->dri.drawable->h; 84 UNLOCK_HARDWARE( rmesa ); 85} 86 87/* Return various strings for glGetString(). 88 */ 89static const GLubyte *radeonGetString( GLcontext *ctx, GLenum name ) 90{ 91 radeonContextPtr rmesa = RADEON_CONTEXT(ctx); 92 static char buffer[128]; 93 unsigned offset; 94 GLuint agp_mode = rmesa->radeonScreen->IsPCI ? 0 : 95 rmesa->radeonScreen->AGPMode; 96 97 switch ( name ) { 98 case GL_VENDOR: 99 return (GLubyte *)"Tungsten Graphics, Inc."; 100 101 case GL_RENDERER: 102 offset = driGetRendererString( buffer, "Radeon", DRIVER_DATE, 103 agp_mode ); 104 105 sprintf( & buffer[ offset ], "%sTCL", 106 !(rmesa->TclFallback & RADEON_TCL_FALLBACK_TCL_DISABLE) 107 ? "" : "NO-" ); 108 109 return (GLubyte *)buffer; 110 111 default: 112 return NULL; 113 } 114} 115 116 117/* Extension strings exported by the R100 driver. 118 */ 119static const char * const card_extensions[] = 120{ 121 "GL_ARB_multisample", 122 "GL_ARB_multitexture", 123 "GL_ARB_texture_border_clamp", 124 "GL_ARB_texture_compression", 125 "GL_ARB_texture_env_add", 126 "GL_ARB_texture_env_combine", 127 "GL_ARB_texture_env_dot3", 128 "GL_ARB_texture_mirrored_repeat", 129 "GL_EXT_blend_logic_op", 130 "GL_EXT_blend_subtract", 131 "GL_EXT_secondary_color", 132 "GL_EXT_texture_edge_clamp", 133 "GL_EXT_texture_env_add", 134 "GL_EXT_texture_env_combine", 135 "GL_EXT_texture_env_dot3", 136 "GL_EXT_texture_filter_anisotropic", 137 "GL_EXT_texture_lod_bias", 138 "GL_ATI_texture_env_combine3", 139 "GL_ATI_texture_mirror_once", 140 "GL_IBM_texture_mirrored_repeat", 141 "GL_MESA_ycbcr_texture", 142 "GL_NV_blend_square", 143 "GL_SGIS_generate_mipmap", 144 "GL_SGIS_texture_border_clamp", 145 "GL_SGIS_texture_edge_clamp", 146 NULL 147}; 148 149extern const struct tnl_pipeline_stage _radeon_texrect_stage; 150extern const struct tnl_pipeline_stage _radeon_render_stage; 151extern const struct tnl_pipeline_stage _radeon_tcl_stage; 152 153static const struct tnl_pipeline_stage *radeon_pipeline[] = { 154 155 /* Try and go straight to t&l 156 */ 157 &_radeon_tcl_stage, 158 159 /* Catch any t&l fallbacks 160 */ 161 &_tnl_vertex_transform_stage, 162 &_tnl_normal_transform_stage, 163 &_tnl_lighting_stage, 164 &_tnl_fog_coordinate_stage, 165 &_tnl_texgen_stage, 166 &_tnl_texture_transform_stage, 167 168 /* Scale texture rectangle to 0..1. 169 */ 170 &_radeon_texrect_stage, 171 172 &_radeon_render_stage, 173 &_tnl_render_stage, /* FALLBACK: */ 174 0, 175}; 176 177 178 179/* Initialize the driver's misc functions. 180 */ 181static void radeonInitDriverFuncs( GLcontext *ctx ) 182{ 183 ctx->Driver.GetBufferSize = radeonGetBufferSize; 184 ctx->Driver.ResizeBuffers = _swrast_alloc_buffers; 185 ctx->Driver.GetString = radeonGetString; 186 187 ctx->Driver.Error = NULL; 188 ctx->Driver.DrawPixels = NULL; 189 ctx->Driver.Bitmap = NULL; 190} 191 192static const struct dri_debug_control debug_control[] = 193{ 194 { "fall", DEBUG_FALLBACKS }, 195 { "tex", DEBUG_TEXTURE }, 196 { "ioctl", DEBUG_IOCTL }, 197 { "prim", DEBUG_PRIMS }, 198 { "vert", DEBUG_VERTS }, 199 { "state", DEBUG_STATE }, 200 { "code", DEBUG_CODEGEN }, 201 { "vfmt", DEBUG_VFMT }, 202 { "vtxf", DEBUG_VFMT }, 203 { "verb", DEBUG_VERBOSE }, 204 { "dri", DEBUG_DRI }, 205 { "dma", DEBUG_DMA }, 206 { "san", DEBUG_SANITY }, 207 { NULL, 0 } 208}; 209 210 211static int 212get_ust_nop( int64_t * ust ) 213{ 214 *ust = 1; 215 return 0; 216} 217 218 219/* Create the device specific context. 220 */ 221GLboolean 222radeonCreateContext( const __GLcontextModes *glVisual, 223 __DRIcontextPrivate *driContextPriv, 224 void *sharedContextPrivate) 225{ 226 __DRIscreenPrivate *sPriv = driContextPriv->driScreenPriv; 227 radeonScreenPtr screen = (radeonScreenPtr)(sPriv->private); 228 radeonContextPtr rmesa; 229 GLcontext *ctx, *shareCtx; 230 int i; 231 int tcl_mode, fthrottle_mode; 232 233 assert(glVisual); 234 assert(driContextPriv); 235 assert(screen); 236 237 /* Allocate the Radeon context */ 238 rmesa = (radeonContextPtr) CALLOC( sizeof(*rmesa) ); 239 if ( !rmesa ) 240 return GL_FALSE; 241 242 /* Allocate the Mesa context */ 243 if (sharedContextPrivate) 244 shareCtx = ((radeonContextPtr) sharedContextPrivate)->glCtx; 245 else 246 shareCtx = NULL; 247 rmesa->glCtx = _mesa_create_context(glVisual, shareCtx, (void *) rmesa, GL_TRUE); 248 if (!rmesa->glCtx) { 249 FREE(rmesa); 250 return GL_FALSE; 251 } 252 driContextPriv->driverPrivate = rmesa; 253 254 /* Init radeon context data */ 255 rmesa->dri.context = driContextPriv; 256 rmesa->dri.screen = sPriv; 257 rmesa->dri.drawable = NULL; /* Set by XMesaMakeCurrent */ 258 rmesa->dri.hwContext = driContextPriv->hHWContext; 259 rmesa->dri.hwLock = &sPriv->pSAREA->lock; 260 rmesa->dri.fd = sPriv->fd; 261 rmesa->dri.drmMinor = sPriv->drmMinor; 262 263 /* Parse configuration files */ 264 driParseConfigFiles (&rmesa->optionCache, &screen->optionCache, 265 screen->driScreen->myNum, "radeon"); 266 267 rmesa->radeonScreen = screen; 268 rmesa->sarea = (RADEONSAREAPrivPtr)((GLubyte *)sPriv->pSAREA + 269 screen->sarea_priv_offset); 270 271 272 rmesa->dma.buf0_address = rmesa->radeonScreen->buffers->list[0].address; 273 274 (void) memset( rmesa->texture_heaps, 0, sizeof( rmesa->texture_heaps ) ); 275 make_empty_list( & rmesa->swapped ); 276 277 rmesa->nr_heaps = screen->numTexHeaps; 278 for ( i = 0 ; i < rmesa->nr_heaps ; i++ ) { 279 rmesa->texture_heaps[i] = driCreateTextureHeap( i, rmesa, 280 screen->texSize[i], 281 12, 282 RADEON_NR_TEX_REGIONS, 283 rmesa->sarea->texList[i], 284 & rmesa->sarea->texAge[i], 285 & rmesa->swapped, 286 sizeof( radeonTexObj ), 287 (destroy_texture_object_t *) radeonDestroyTexObj ); 288 289 driSetTextureSwapCounterLocation( rmesa->texture_heaps[i], 290 & rmesa->c_textureSwaps ); 291 } 292 rmesa->texture_depth = driQueryOptioni (&rmesa->optionCache, 293 "texture_depth"); 294 if (rmesa->texture_depth == DRI_CONF_TEXTURE_DEPTH_FB) 295 rmesa->texture_depth = ( screen->cpp == 4 ) ? 296 DRI_CONF_TEXTURE_DEPTH_32 : DRI_CONF_TEXTURE_DEPTH_16; 297 298 rmesa->swtcl.RenderIndex = ~0; 299 rmesa->lost_context = 1; 300 301 /* Set the maximum texture size small enough that we can guarentee that 302 * all texture units can bind a maximal texture and have them both in 303 * texturable memory at once. 304 */ 305 306 ctx = rmesa->glCtx; 307 ctx->Const.MaxTextureUnits = 2; 308 ctx->Const.MaxTextureImageUnits = 2; 309 ctx->Const.MaxTextureCoordUnits = 2; 310 311 driCalculateMaxTextureLevels( rmesa->texture_heaps, 312 rmesa->nr_heaps, 313 & ctx->Const, 314 4, 315 11, /* max 2D texture size is 2048x2048 */ 316 0, /* 3D textures unsupported. */ 317 0, /* cube textures unsupported. */ 318 11, /* max rect texture size is 2048x2048. */ 319 12, 320 GL_FALSE ); 321 322 ctx->Const.MaxTextureMaxAnisotropy = 16.0; 323 324 /* No wide points. 325 */ 326 ctx->Const.MinPointSize = 1.0; 327 ctx->Const.MinPointSizeAA = 1.0; 328 ctx->Const.MaxPointSize = 1.0; 329 ctx->Const.MaxPointSizeAA = 1.0; 330 331 ctx->Const.MinLineWidth = 1.0; 332 ctx->Const.MinLineWidthAA = 1.0; 333 ctx->Const.MaxLineWidth = 10.0; 334 ctx->Const.MaxLineWidthAA = 10.0; 335 ctx->Const.LineWidthGranularity = 0.0625; 336 337 /* Set maxlocksize (and hence vb size) small enough to avoid 338 * fallbacks in radeon_tcl.c. ie. guarentee that all vertices can 339 * fit in a single dma buffer for indexed rendering of quad strips, 340 * etc. 341 */ 342 ctx->Const.MaxArrayLockSize = 343 MIN2( ctx->Const.MaxArrayLockSize, 344 RADEON_BUFFER_SIZE / RADEON_MAX_TCL_VERTSIZE ); 345 346 rmesa->boxes = 0; 347 348 /* Initialize the software rasterizer and helper modules. 349 */ 350 _swrast_CreateContext( ctx ); 351 _ac_CreateContext( ctx ); 352 _tnl_CreateContext( ctx ); 353 _swsetup_CreateContext( ctx ); 354 _ae_create_context( ctx ); 355 356 /* Install the customized pipeline: 357 */ 358 _tnl_destroy_pipeline( ctx ); 359 _tnl_install_pipeline( ctx, radeon_pipeline ); 360 ctx->Driver.FlushVertices = radeonFlushVertices; 361 362 /* Try and keep materials and vertices separate: 363 */ 364 _tnl_isolate_materials( ctx, GL_TRUE ); 365 366 367/* _mesa_allow_light_in_model( ctx, GL_FALSE ); */ 368 369 /* Try and keep materials and vertices separate: 370 */ 371 _tnl_isolate_materials( ctx, GL_TRUE ); 372 373 374 /* Configure swrast to match hardware characteristics: 375 */ 376 _swrast_allow_pixel_fog( ctx, GL_FALSE ); 377 _swrast_allow_vertex_fog( ctx, GL_TRUE ); 378 379 380 _math_matrix_ctr( &rmesa->TexGenMatrix[0] ); 381 _math_matrix_ctr( &rmesa->TexGenMatrix[1] ); 382 _math_matrix_ctr( &rmesa->tmpmat ); 383 _math_matrix_set_identity( &rmesa->TexGenMatrix[0] ); 384 _math_matrix_set_identity( &rmesa->TexGenMatrix[1] ); 385 _math_matrix_set_identity( &rmesa->tmpmat ); 386 387 driInitExtensions( ctx, card_extensions, GL_TRUE ); 388 389 if (rmesa->dri.drmMinor >= 9) 390 _mesa_enable_extension( ctx, "GL_NV_texture_rectangle"); 391 392 radeonInitDriverFuncs( ctx ); 393 radeonInitIoctlFuncs( ctx ); 394 radeonInitStateFuncs( ctx ); 395 radeonInitSpanFuncs( ctx ); 396 radeonInitTextureFuncs( ctx ); 397 radeonInitState( rmesa ); 398 radeonInitSwtcl( ctx ); 399 400 _mesa_vector4f_alloc( &rmesa->tcl.ObjClean, 0, 401 ctx->Const.MaxArrayLockSize, 32 ); 402 403 fthrottle_mode = driQueryOptioni(&rmesa->optionCache, "fthrottle_mode"); 404 rmesa->iw.irq_seq = -1; 405 rmesa->irqsEmitted = 0; 406 rmesa->do_irqs = (rmesa->radeonScreen->irq != 0 && 407 fthrottle_mode == DRI_CONF_FTHROTTLE_IRQS); 408 409 rmesa->do_usleeps = (fthrottle_mode == DRI_CONF_FTHROTTLE_USLEEPS); 410 411 rmesa->vblank_flags = (rmesa->radeonScreen->irq != 0) 412 ? driGetDefaultVBlankFlags(&rmesa->optionCache) : VBLANK_FLAG_NO_IRQ; 413#ifndef _SOLO 414 rmesa->get_ust = (PFNGLXGETUSTPROC) glXGetProcAddress( (const GLubyte *) "__glXGetUST" ); 415 if ( rmesa->get_ust == NULL ) { 416 rmesa->get_ust = get_ust_nop; 417 } 418#else 419 rmesa->get_ust = get_ust_nop; 420#endif 421 422 (*rmesa->get_ust)( & rmesa->swap_ust ); 423 424 425#if DO_DEBUG 426 RADEON_DEBUG = driParseDebugString( getenv( "RADEON_DEBUG" ), 427 debug_control ); 428#endif 429 430 tcl_mode = driQueryOptioni(&rmesa->optionCache, "tcl_mode"); 431 if (driQueryOptionb(&rmesa->optionCache, "no_rast")) { 432 fprintf(stderr, "disabling 3D acceleration\n"); 433 FALLBACK(rmesa, RADEON_FALLBACK_DISABLE, 1); 434 } else if (tcl_mode == DRI_CONF_TCL_SW || 435 !(rmesa->radeonScreen->chipset & RADEON_CHIPSET_TCL)) { 436 rmesa->radeonScreen->chipset &= ~RADEON_CHIPSET_TCL; 437 fprintf(stderr, "disabling TCL support\n"); 438 TCL_FALLBACK(rmesa->glCtx, RADEON_TCL_FALLBACK_TCL_DISABLE, 1); 439 } 440 441 if (rmesa->radeonScreen->chipset & RADEON_CHIPSET_TCL) { 442 if (tcl_mode >= DRI_CONF_TCL_VTXFMT) 443 radeonVtxfmtInit( ctx, tcl_mode >= DRI_CONF_TCL_CODEGEN ); 444 445 _tnl_need_dlist_norm_lengths( ctx, GL_FALSE ); 446 } 447 return GL_TRUE; 448} 449 450 451/* Destroy the device specific context. 452 */ 453/* Destroy the Mesa and driver specific context data. 454 */ 455void radeonDestroyContext( __DRIcontextPrivate *driContextPriv ) 456{ 457 GET_CURRENT_CONTEXT(ctx); 458 radeonContextPtr rmesa = (radeonContextPtr) driContextPriv->driverPrivate; 459 radeonContextPtr current = ctx ? RADEON_CONTEXT(ctx) : NULL; 460 461 /* check if we're deleting the currently bound context */ 462 if (rmesa == current) { 463 RADEON_FIREVERTICES( rmesa ); 464 _mesa_make_current2(NULL, NULL, NULL); 465 } 466 467 /* Free radeon context resources */ 468 assert(rmesa); /* should never be null */ 469 if ( rmesa ) { 470 GLboolean release_texture_heaps; 471 472 473 release_texture_heaps = (rmesa->glCtx->Shared->RefCount == 1); 474 _swsetup_DestroyContext( rmesa->glCtx ); 475 _tnl_DestroyContext( rmesa->glCtx ); 476 _ac_DestroyContext( rmesa->glCtx ); 477 _swrast_DestroyContext( rmesa->glCtx ); 478 479 radeonDestroySwtcl( rmesa->glCtx ); 480 radeonReleaseArrays( rmesa->glCtx, ~0 ); 481 if (rmesa->dma.current.buf) { 482 radeonReleaseDmaRegion( rmesa, &rmesa->dma.current, __FUNCTION__ ); 483 radeonFlushCmdBuf( rmesa, __FUNCTION__ ); 484 } 485 486 if (!(rmesa->TclFallback & RADEON_TCL_FALLBACK_TCL_DISABLE)) { 487 int tcl_mode = driQueryOptioni(&rmesa->optionCache, "tcl_mode"); 488 if (tcl_mode >= DRI_CONF_TCL_VTXFMT) 489 radeonVtxfmtDestroy( rmesa->glCtx ); 490 } 491 492 /* free the Mesa context */ 493 rmesa->glCtx->DriverCtx = NULL; 494 _mesa_destroy_context( rmesa->glCtx ); 495 496 _mesa_vector4f_free( &rmesa->tcl.ObjClean ); 497 498 if (rmesa->state.scissor.pClipRects) { 499 FREE(rmesa->state.scissor.pClipRects); 500 rmesa->state.scissor.pClipRects = 0; 501 } 502 503 if ( release_texture_heaps ) { 504 /* This share group is about to go away, free our private 505 * texture object data. 506 */ 507 int i; 508 509 for ( i = 0 ; i < rmesa->nr_heaps ; i++ ) { 510 driDestroyTextureHeap( rmesa->texture_heaps[ i ] ); 511 rmesa->texture_heaps[ i ] = NULL; 512 } 513 514 assert( is_empty_list( & rmesa->swapped ) ); 515 } 516 517 /* free the option cache */ 518 driDestroyOptionCache (&rmesa->optionCache); 519 520 FREE( rmesa ); 521 } 522} 523 524 525 526 527void 528radeonSwapBuffers( __DRIdrawablePrivate *dPriv ) 529{ 530 531 if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) { 532 radeonContextPtr rmesa; 533 GLcontext *ctx; 534 rmesa = (radeonContextPtr) dPriv->driContextPriv->driverPrivate; 535 ctx = rmesa->glCtx; 536 if (ctx->Visual.doubleBufferMode) { 537 _mesa_notifySwapBuffers( ctx ); /* flush pending rendering comands */ 538 539 if ( rmesa->doPageFlip ) { 540 radeonPageFlip( dPriv ); 541 } 542 else { 543 radeonCopyBuffer( dPriv ); 544 } 545 } 546 } 547 else { 548 /* XXX this shouldn't be an error but we can't handle it for now */ 549 _mesa_problem(NULL, "%s: drawable has no context!", __FUNCTION__); 550 } 551} 552 553 554/* Force the context `c' to be the current context and associate with it 555 * buffer `b'. 556 */ 557GLboolean 558radeonMakeCurrent( __DRIcontextPrivate *driContextPriv, 559 __DRIdrawablePrivate *driDrawPriv, 560 __DRIdrawablePrivate *driReadPriv ) 561{ 562 if ( driContextPriv ) { 563 radeonContextPtr newCtx = 564 (radeonContextPtr) driContextPriv->driverPrivate; 565 566 if (RADEON_DEBUG & DEBUG_DRI) 567 fprintf(stderr, "%s ctx %p\n", __FUNCTION__, newCtx->glCtx); 568 569 if ( newCtx->dri.drawable != driDrawPriv ) { 570 driDrawableInitVBlank( driDrawPriv, newCtx->vblank_flags ); 571 newCtx->dri.drawable = driDrawPriv; 572 radeonUpdateWindow( newCtx->glCtx ); 573 radeonUpdateViewportOffset( newCtx->glCtx ); 574 } 575 576 _mesa_make_current2( newCtx->glCtx, 577 (GLframebuffer *) driDrawPriv->driverPrivate, 578 (GLframebuffer *) driReadPriv->driverPrivate ); 579 580 if ( !newCtx->glCtx->Viewport.Width ) { 581 _mesa_set_viewport( newCtx->glCtx, 0, 0, 582 driDrawPriv->w, driDrawPriv->h ); 583 } 584 585 if (newCtx->vb.enabled) 586 radeonVtxfmtMakeCurrent( newCtx->glCtx ); 587 588 } else { 589 if (RADEON_DEBUG & DEBUG_DRI) 590 fprintf(stderr, "%s ctx is null\n", __FUNCTION__); 591 _mesa_make_current( 0, 0 ); 592 } 593 594 if (RADEON_DEBUG & DEBUG_DRI) 595 fprintf(stderr, "End %s\n", __FUNCTION__); 596 return GL_TRUE; 597} 598 599/* Force the context `c' to be unbound from its buffer. 600 */ 601GLboolean 602radeonUnbindContext( __DRIcontextPrivate *driContextPriv ) 603{ 604 radeonContextPtr rmesa = (radeonContextPtr) driContextPriv->driverPrivate; 605 606 if (RADEON_DEBUG & DEBUG_DRI) 607 fprintf(stderr, "%s ctx %p\n", __FUNCTION__, rmesa->glCtx); 608 609 return GL_TRUE; 610} 611