GalliumContext.cpp revision af69d88d
1/* 2 * Copyright 2012, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Artur Wyszynski, harakash@gmail.com 7 * Alexander von Gluck IV, kallisti5@unixzen.com 8 */ 9 10 11#include "GalliumContext.h" 12 13#include "GLView.h" 14 15#include "bitmap_wrapper.h" 16extern "C" { 17#include "glapi/glapi.h" 18#include "main/context.h" 19#include "main/framebuffer.h" 20#include "main/renderbuffer.h" 21#include "main/viewport.h" 22#include "pipe/p_format.h" 23#include "state_tracker/st_cb_fbo.h" 24#include "state_tracker/st_cb_flush.h" 25#include "state_tracker/st_context.h" 26#include "state_tracker/st_gl_api.h" 27#include "state_tracker/st_manager.h" 28#include "state_tracker/sw_winsys.h" 29#include "util/u_memory.h" 30#include "hgl_sw_winsys.h" 31 32#include "target-helpers/inline_sw_helper.h" 33#include "target-helpers/inline_debug_helper.h" 34} 35 36 37#ifdef DEBUG 38# define TRACE(x...) printf("GalliumContext: " x) 39# define CALLED() TRACE("CALLED: %s\n", __PRETTY_FUNCTION__) 40#else 41# define TRACE(x...) 42# define CALLED() 43#endif 44#define ERROR(x...) printf("GalliumContext: " x) 45 46 47static void 48hgl_viewport(struct gl_context* glContext) 49{ 50 // TODO: We should try to eliminate this function 51 52 GLint x = glContext->ViewportArray[0].X; 53 GLint y = glContext->ViewportArray[0].Y; 54 GLint width = glContext->ViewportArray[0].Width; 55 GLint height = glContext->ViewportArray[0].Height; 56 57 TRACE("%s(glContext: %p, x: %d, y: %d, w: %d, h: %d\n", __func__, 58 glContext, x, y, width, height); 59 60 _mesa_check_init_viewport(glContext, width, height); 61 62 struct gl_framebuffer *draw = glContext->WinSysDrawBuffer; 63 struct gl_framebuffer *read = glContext->WinSysReadBuffer; 64 65 if (draw) 66 _mesa_resize_framebuffer(glContext, draw, width, height); 67 if (read) 68 _mesa_resize_framebuffer(glContext, read, width, height); 69} 70 71 72static st_visual* 73hgl_fill_st_visual(gl_config* glVisual) 74{ 75 struct st_visual* stVisual = CALLOC_STRUCT(st_visual); 76 if (!stVisual) { 77 ERROR("%s: Couldn't allocate st_visual\n", __func__); 78 return NULL; 79 } 80 81 // Determine color format 82 if (glVisual->redBits == 8) { 83 if (glVisual->alphaBits == 8) 84 stVisual->color_format = PIPE_FORMAT_A8R8G8B8_UNORM; 85 else 86 stVisual->color_format = PIPE_FORMAT_X8R8G8B8_UNORM; 87 } else { 88 // TODO: I think this should be RGB vs BGR 89 stVisual->color_format = PIPE_FORMAT_B5G6R5_UNORM; 90 } 91 92 // Determine depth stencil format 93 switch (glVisual->depthBits) { 94 default: 95 case 0: 96 stVisual->depth_stencil_format = PIPE_FORMAT_NONE; 97 break; 98 case 16: 99 stVisual->depth_stencil_format = PIPE_FORMAT_Z16_UNORM; 100 break; 101 case 24: 102 if (glVisual->stencilBits == 0) { 103 stVisual->depth_stencil_format = PIPE_FORMAT_X8Z24_UNORM; 104 } else { 105 stVisual->depth_stencil_format = PIPE_FORMAT_S8_UINT_Z24_UNORM; 106 } 107 break; 108 case 32: 109 stVisual->depth_stencil_format = PIPE_FORMAT_Z32_UNORM; 110 break; 111 } 112 113 stVisual->accum_format = (glVisual->haveAccumBuffer) 114 ? PIPE_FORMAT_R16G16B16A16_SNORM : PIPE_FORMAT_NONE; 115 116 stVisual->buffer_mask |= ST_ATTACHMENT_FRONT_LEFT_MASK; 117 stVisual->render_buffer = ST_ATTACHMENT_FRONT_LEFT; 118 if (glVisual->doubleBufferMode) { 119 stVisual->buffer_mask |= ST_ATTACHMENT_BACK_LEFT_MASK; 120 stVisual->render_buffer = ST_ATTACHMENT_BACK_LEFT; 121 } 122 123 if (glVisual->stereoMode) { 124 stVisual->buffer_mask |= ST_ATTACHMENT_FRONT_RIGHT_MASK; 125 if (glVisual->doubleBufferMode) 126 stVisual->buffer_mask |= ST_ATTACHMENT_BACK_RIGHT_MASK; 127 } 128 129 if (glVisual->haveDepthBuffer || glVisual->haveStencilBuffer) 130 stVisual->buffer_mask |= ST_ATTACHMENT_DEPTH_STENCIL_MASK; 131 132 return stVisual; 133} 134 135 136static int 137hook_stm_get_param(struct st_manager *smapi, enum st_manager_param param) 138{ 139 CALLED(); 140 141 switch (param) { 142 case ST_MANAGER_BROKEN_INVALIDATE: 143 TRACE("%s: TODO: How should we handle BROKEN_INVALIDATE calls?\n", 144 __func__); 145 // For now we force validation of the framebuffer. 146 return 1; 147 } 148 149 return 0; 150} 151 152 153GalliumContext::GalliumContext(ulong options) 154 : 155 fOptions(options), 156 fScreen(NULL), 157 fCurrentContext(0) 158{ 159 CALLED(); 160 161 // Make all contexts a known value 162 for (context_id i = 0; i < CONTEXT_MAX; i++) 163 fContext[i] = NULL; 164 165 CreateScreen(); 166 167 pipe_mutex_init(fMutex); 168} 169 170 171GalliumContext::~GalliumContext() 172{ 173 CALLED(); 174 175 // Destroy our contexts 176 Lock(); 177 for (context_id i = 0; i < CONTEXT_MAX; i++) 178 DestroyContext(i); 179 Unlock(); 180 181 pipe_mutex_destroy(fMutex); 182 183 // TODO: Destroy fScreen 184} 185 186 187status_t 188GalliumContext::CreateScreen() 189{ 190 CALLED(); 191 192 // Allocate winsys and attach callback hooks 193 struct sw_winsys* winsys = hgl_create_sw_winsys(); 194 195 if (!winsys) { 196 ERROR("%s: Couldn't allocate sw_winsys!\n", __func__); 197 return B_ERROR; 198 } 199 200 fScreen = sw_screen_create(winsys); 201 202 if (fScreen == NULL) { 203 ERROR("%s: Couldn't create screen!\n", __FUNCTION__); 204 FREE(winsys); 205 return B_ERROR; 206 } 207 208 debug_screen_wrap(fScreen); 209 210 const char* driverName = fScreen->get_name(fScreen); 211 ERROR("%s: Using %s driver.\n", __func__, driverName); 212 213 return B_OK; 214} 215 216 217context_id 218GalliumContext::CreateContext(Bitmap *bitmap) 219{ 220 CALLED(); 221 222 struct hgl_context* context = CALLOC_STRUCT(hgl_context); 223 224 if (!context) { 225 ERROR("%s: Couldn't create pipe context!\n", __FUNCTION__); 226 return 0; 227 } 228 229 // Set up the initial things our context needs 230 context->bitmap = bitmap; 231 context->colorSpace = get_bitmap_color_space(bitmap); 232 context->draw = NULL; 233 context->read = NULL; 234 context->st = NULL; 235 236 context->api = st_gl_api_create(); 237 if (!context->api) { 238 ERROR("%s: Couldn't obtain Mesa state tracker API!\n", __func__); 239 return -1; 240 } 241 242 context->manager = CALLOC_STRUCT(st_manager); 243 if (!context->manager) { 244 ERROR("%s: Couldn't allocate Mesa state tracker manager!\n", __func__); 245 return -1; 246 } 247 context->manager->get_param = hook_stm_get_param; 248 249 // Calculate visual configuration 250 const GLboolean rgbFlag = ((fOptions & BGL_INDEX) == 0); 251 const GLboolean alphaFlag = ((fOptions & BGL_ALPHA) == BGL_ALPHA); 252 const GLboolean dblFlag = ((fOptions & BGL_DOUBLE) == BGL_DOUBLE); 253 const GLboolean stereoFlag = false; 254 const GLint depth = (fOptions & BGL_DEPTH) ? 24 : 0; 255 const GLint stencil = (fOptions & BGL_STENCIL) ? 8 : 0; 256 const GLint accum = (fOptions & BGL_ACCUM) ? 16 : 0; 257 const GLint red = rgbFlag ? 8 : 5; 258 const GLint green = rgbFlag ? 8 : 5; 259 const GLint blue = rgbFlag ? 8 : 5; 260 const GLint alpha = alphaFlag ? 8 : 0; 261 262 TRACE("rgb :\t%d\n", (bool)rgbFlag); 263 TRACE("alpha :\t%d\n", (bool)alphaFlag); 264 TRACE("dbl :\t%d\n", (bool)dblFlag); 265 TRACE("stereo :\t%d\n", (bool)stereoFlag); 266 TRACE("depth :\t%d\n", depth); 267 TRACE("stencil :\t%d\n", stencil); 268 TRACE("accum :\t%d\n", accum); 269 TRACE("red :\t%d\n", red); 270 TRACE("green :\t%d\n", green); 271 TRACE("blue :\t%d\n", blue); 272 TRACE("alpha :\t%d\n", alpha); 273 274 gl_config* glVisual = _mesa_create_visual(dblFlag, stereoFlag, red, green, 275 blue, alpha, depth, stencil, accum, accum, accum, alpha ? accum : 0, 1); 276 277 if (!glVisual) { 278 ERROR("%s: Couldn't create Mesa visual!\n", __func__); 279 return -1; 280 } 281 282 TRACE("depthBits :\t%d\n", glVisual->depthBits); 283 TRACE("stencilBits :\t%d\n", glVisual->stencilBits); 284 285 // Convert Mesa calculated visual into state tracker visual 286 context->stVisual = hgl_fill_st_visual(glVisual); 287 288 context->draw = new GalliumFramebuffer(context->stVisual, (void*)this); 289 context->read = new GalliumFramebuffer(context->stVisual, (void*)this); 290 291 if (!context->draw || !context->read) { 292 ERROR("%s: Problem allocating framebuffer!\n", __func__); 293 _mesa_destroy_visual(glVisual); 294 return -1; 295 } 296 297 // We need to assign the screen *before* calling st_api create_context 298 context->manager->screen = fScreen; 299 300 // Build state tracker attributes 301 struct st_context_attribs attribs; 302 memset(&attribs, 0, sizeof(attribs)); 303 attribs.options.force_glsl_extensions_warn = false; 304 attribs.profile = ST_PROFILE_DEFAULT; 305 attribs.visual = *context->stVisual; 306 attribs.major = 1; 307 attribs.minor = 0; 308 //attribs.flags |= ST_CONTEXT_FLAG_DEBUG; 309 310 struct st_api* api = context->api; 311 312 // Create context using state tracker api call 313 enum st_context_error result; 314 context->st = api->create_context(api, context->manager, &attribs, 315 &result, context->st); 316 317 if (!context->st) { 318 ERROR("%s: Couldn't create mesa state tracker context!\n", 319 __func__); 320 switch (result) { 321 case ST_CONTEXT_SUCCESS: 322 ERROR("%s: State tracker error: SUCCESS?\n", __func__); 323 break; 324 case ST_CONTEXT_ERROR_NO_MEMORY: 325 ERROR("%s: State tracker error: NO_MEMORY\n", __func__); 326 break; 327 case ST_CONTEXT_ERROR_BAD_API: 328 ERROR("%s: State tracker error: BAD_API\n", __func__); 329 break; 330 case ST_CONTEXT_ERROR_BAD_VERSION: 331 ERROR("%s: State tracker error: BAD_VERSION\n", __func__); 332 break; 333 case ST_CONTEXT_ERROR_BAD_FLAG: 334 ERROR("%s: State tracker error: BAD_FLAG\n", __func__); 335 break; 336 case ST_CONTEXT_ERROR_UNKNOWN_ATTRIBUTE: 337 ERROR("%s: State tracker error: BAD_ATTRIBUTE\n", __func__); 338 break; 339 case ST_CONTEXT_ERROR_UNKNOWN_FLAG: 340 ERROR("%s: State tracker error: UNKNOWN_FLAG\n", __func__); 341 break; 342 } 343 344 FREE(context); 345 return -1; 346 } 347 348 assert(!context->st->st_manager_private); 349 context->st->st_manager_private = (void*)context; 350 351 struct st_context *stContext = (struct st_context*)context->st; 352 353 stContext->ctx->Driver.Viewport = hgl_viewport; 354 355 // Init Gallium3D Post Processing 356 // TODO: no pp filters are enabled yet through postProcessEnable 357 context->postProcess = pp_init(stContext->pipe, context->postProcessEnable, 358 stContext->cso_context); 359 360 context_id contextNext = -1; 361 Lock(); 362 for (context_id i = 0; i < CONTEXT_MAX; i++) { 363 if (fContext[i] == NULL) { 364 fContext[i] = context; 365 contextNext = i; 366 break; 367 } 368 } 369 Unlock(); 370 371 if (contextNext < 0) { 372 ERROR("%s: The next context is invalid... something went wrong!\n", 373 __func__); 374 //st_destroy_context(context->st); 375 FREE(context); 376 _mesa_destroy_visual(glVisual); 377 return -1; 378 } 379 380 TRACE("%s: context #%" B_PRIu64 " is the next available context\n", 381 __func__, contextNext); 382 383 return contextNext; 384} 385 386 387void 388GalliumContext::DestroyContext(context_id contextID) 389{ 390 // fMutex should be locked *before* calling DestoryContext 391 392 // See if context is used 393 if (!fContext[contextID]) 394 return; 395 396 if (fContext[contextID]->st) { 397 fContext[contextID]->st->flush(fContext[contextID]->st, 0, NULL); 398 fContext[contextID]->st->destroy(fContext[contextID]->st); 399 } 400 401 if (fContext[contextID]->postProcess) 402 pp_free(fContext[contextID]->postProcess); 403 404 // Delete framebuffer objects 405 if (fContext[contextID]->read) 406 delete fContext[contextID]->read; 407 if (fContext[contextID]->draw) 408 delete fContext[contextID]->draw; 409 410 if (fContext[contextID]->stVisual) 411 FREE(fContext[contextID]->stVisual); 412 413 if (fContext[contextID]->manager) 414 FREE(fContext[contextID]->manager); 415 416 FREE(fContext[contextID]); 417} 418 419 420status_t 421GalliumContext::SetCurrentContext(Bitmap *bitmap, context_id contextID) 422{ 423 CALLED(); 424 425 if (contextID < 0 || contextID > CONTEXT_MAX) { 426 ERROR("%s: Invalid context ID range!\n", __func__); 427 return B_ERROR; 428 } 429 430 Lock(); 431 context_id oldContextID = fCurrentContext; 432 struct hgl_context* context = fContext[contextID]; 433 Unlock(); 434 435 if (!context) { 436 ERROR("%s: Invalid context provided (#%" B_PRIu64 ")!\n", 437 __func__, contextID); 438 return B_ERROR; 439 } 440 441 struct st_api* api = context->api; 442 443 if (!bitmap) { 444 api->make_current(context->api, NULL, NULL, NULL); 445 return B_OK; 446 } 447 448 // Everything seems valid, lets set the new context. 449 fCurrentContext = contextID; 450 451 if (oldContextID > 0 && oldContextID != contextID) { 452 fContext[oldContextID]->st->flush(fContext[oldContextID]->st, 453 ST_FLUSH_FRONT, NULL); 454 } 455 456 // We need to lock and unlock framebuffers before accessing them 457 context->draw->Lock(); 458 context->read->Lock(); 459 api->make_current(context->api, context->st, context->draw->fBuffer, 460 context->read->fBuffer); 461 context->draw->Unlock(); 462 context->read->Unlock(); 463 464 if (context->textures[ST_ATTACHMENT_BACK_LEFT] 465 && context->textures[ST_ATTACHMENT_DEPTH_STENCIL] 466 && context->postProcess) { 467 TRACE("Postprocessing textures...\n"); 468 pp_init_fbos(context->postProcess, 469 context->textures[ST_ATTACHMENT_BACK_LEFT]->width0, 470 context->textures[ST_ATTACHMENT_BACK_LEFT]->height0); 471 } 472 473 context->bitmap = bitmap; 474 //context->st->pipe->priv = context; 475 476 return B_OK; 477} 478 479 480status_t 481GalliumContext::SwapBuffers(context_id contextID) 482{ 483 CALLED(); 484 485 Lock(); 486 struct hgl_context *context = fContext[contextID]; 487 Unlock(); 488 489 if (!context) { 490 ERROR("%s: context not found\n", __func__); 491 return B_ERROR; 492 } 493 494 // TODO: Where did st_notify_swapbuffers go? 495 //st_notify_swapbuffers(context->draw->stfb); 496 497 context->st->flush(context->st, ST_FLUSH_FRONT, NULL); 498 499 struct st_context *stContext = (struct st_context*)context->st; 500 501 unsigned nColorBuffers = stContext->state.framebuffer.nr_cbufs; 502 for (unsigned i = 0; i < nColorBuffers; i++) { 503 pipe_surface* surface = stContext->state.framebuffer.cbufs[i]; 504 if (!surface) { 505 ERROR("%s: Color buffer %d invalid!\n", __func__, i); 506 continue; 507 } 508 509 TRACE("%s: Flushing color buffer #%d\n", __func__, i); 510 511 // We pass our destination bitmap to flush_fronbuffer which passes it 512 // to the private winsys display call. 513 fScreen->flush_frontbuffer(fScreen, surface->texture, 0, 0, 514 context->bitmap, NULL); 515 } 516 517 #if 0 518 // TODO... should we flush the z stencil buffer? 519 pipe_surface* zSurface = stContext->state.framebuffer.zsbuf; 520 fScreen->flush_frontbuffer(fScreen, zSurface->texture, 0, 0, 521 context->bitmap, NULL); 522 #endif 523 524 return B_OK; 525} 526 527 528void 529GalliumContext::ResizeViewport(int32 width, int32 height) 530{ 531 CALLED(); 532 for (context_id i = 0; i < CONTEXT_MAX; i++) { 533 if (fContext[i] && fContext[i]->st) { 534 struct st_context *stContext = (struct st_context*)fContext[i]->st; 535 _mesa_set_viewport(stContext->ctx, 0, 0, 0, width, height); 536 st_manager_validate_framebuffers(stContext); 537 } 538 } 539} 540 541 542void 543GalliumContext::Lock() 544{ 545 CALLED(); 546 pipe_mutex_lock(fMutex); 547} 548 549 550void 551GalliumContext::Unlock() 552{ 553 CALLED(); 554 pipe_mutex_unlock(fMutex); 555} 556/* vim: set tabstop=4: */ 557