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 (at) gmail.com 7 * Alexander von Gluck IV, kallisti5 (at) unixzen.com 8 */ 9 10 11 #include "GalliumContext.h" 12 13 #include <stdio.h> 14 15 #include "GLView.h" 16 17 #include "bitmap_wrapper.h" 18 19 #include "glapi/glapi.h" 20 #include "pipe/p_format.h" 21 //#include "state_tracker/st_cb_fbo.h" 22 //#include "state_tracker/st_cb_flush.h" 23 #include "state_tracker/st_context.h" 24 #include "state_tracker/st_gl_api.h" 25 #include "state_tracker/sw_winsys.h" 26 #include "sw/hgl/hgl_sw_winsys.h" 27 #include "util/u_atomic.h" 28 #include "util/u_memory.h" 29 30 #include "target-helpers/inline_sw_helper.h" 31 #include "target-helpers/inline_debug_helper.h" 32 33 34 #ifdef DEBUG 35 # define TRACE(x...) printf("GalliumContext: " x) 36 # define CALLED() TRACE("CALLED: %s\n", __PRETTY_FUNCTION__) 37 #else 38 # define TRACE(x...) 39 # define CALLED() 40 #endif 41 #define ERROR(x...) printf("GalliumContext: " x) 42 43 44 GalliumContext::GalliumContext(ulong options) 45 : 46 fOptions(options), 47 fScreen(NULL), 48 fCurrentContext(0) 49 { 50 CALLED(); 51 52 // Make all contexts a known value 53 for (context_id i = 0; i < CONTEXT_MAX; i++) 54 fContext[i] = NULL; 55 56 CreateScreen(); 57 58 pipe_mutex_init(fMutex); 59 } 60 61 62 GalliumContext::~GalliumContext() 63 { 64 CALLED(); 65 66 // Destroy our contexts 67 Lock(); 68 for (context_id i = 0; i < CONTEXT_MAX; i++) 69 DestroyContext(i); 70 Unlock(); 71 72 pipe_mutex_destroy(fMutex); 73 74 // TODO: Destroy fScreen 75 } 76 77 78 status_t 79 GalliumContext::CreateScreen() 80 { 81 CALLED(); 82 83 // Allocate winsys and attach callback hooks 84 struct sw_winsys* winsys = hgl_create_sw_winsys(); 85 86 if (!winsys) { 87 ERROR("%s: Couldn't allocate sw_winsys!\n", __func__); 88 return B_ERROR; 89 } 90 91 fScreen = sw_screen_create(winsys); 92 93 if (fScreen == NULL) { 94 ERROR("%s: Couldn't create screen!\n", __FUNCTION__); 95 FREE(winsys); 96 return B_ERROR; 97 } 98 99 debug_screen_wrap(fScreen); 100 101 const char* driverName = fScreen->get_name(fScreen); 102 ERROR("%s: Using %s driver.\n", __func__, driverName); 103 104 return B_OK; 105 } 106 107 108 context_id 109 GalliumContext::CreateContext(Bitmap *bitmap) 110 { 111 CALLED(); 112 113 struct hgl_context* context = CALLOC_STRUCT(hgl_context); 114 115 if (!context) { 116 ERROR("%s: Couldn't create pipe context!\n", __FUNCTION__); 117 return 0; 118 } 119 120 // Set up the initial things our context needs 121 context->bitmap = bitmap; 122 context->colorSpace = get_bitmap_color_space(bitmap); 123 context->screen = fScreen; 124 context->draw = NULL; 125 context->read = NULL; 126 context->st = NULL; 127 128 // Create st_gl_api 129 context->api = hgl_create_st_api(); 130 if (!context->api) { 131 ERROR("%s: Couldn't obtain Mesa state tracker API!\n", __func__); 132 return -1; 133 } 134 135 // Create state_tracker manager 136 context->manager = hgl_create_st_manager(context); 137 138 // Create state tracker visual 139 context->stVisual = hgl_create_st_visual(fOptions); 140 141 // Create state tracker framebuffers 142 context->draw = hgl_create_st_framebuffer(context); 143 context->read = hgl_create_st_framebuffer(context); 144 145 if (!context->draw || !context->read) { 146 ERROR("%s: Problem allocating framebuffer!\n", __func__); 147 FREE(context->stVisual); 148 return -1; 149 } 150 151 // Build state tracker attributes 152 struct st_context_attribs attribs; 153 memset(&attribs, 0, sizeof(attribs)); 154 attribs.options.force_glsl_extensions_warn = false; 155 attribs.profile = ST_PROFILE_DEFAULT; 156 attribs.visual = *context->stVisual; 157 attribs.major = 1; 158 attribs.minor = 0; 159 //attribs.flags |= ST_CONTEXT_FLAG_DEBUG; 160 161 // Create context using state tracker api call 162 enum st_context_error result; 163 context->st = context->api->create_context(context->api, context->manager, 164 &attribs, &result, context->st); 165 166 if (!context->st) { 167 ERROR("%s: Couldn't create mesa state tracker context!\n", 168 __func__); 169 switch (result) { 170 case ST_CONTEXT_SUCCESS: 171 ERROR("%s: State tracker error: SUCCESS?\n", __func__); 172 break; 173 case ST_CONTEXT_ERROR_NO_MEMORY: 174 ERROR("%s: State tracker error: NO_MEMORY\n", __func__); 175 break; 176 case ST_CONTEXT_ERROR_BAD_API: 177 ERROR("%s: State tracker error: BAD_API\n", __func__); 178 break; 179 case ST_CONTEXT_ERROR_BAD_VERSION: 180 ERROR("%s: State tracker error: BAD_VERSION\n", __func__); 181 break; 182 case ST_CONTEXT_ERROR_BAD_FLAG: 183 ERROR("%s: State tracker error: BAD_FLAG\n", __func__); 184 break; 185 case ST_CONTEXT_ERROR_UNKNOWN_ATTRIBUTE: 186 ERROR("%s: State tracker error: BAD_ATTRIBUTE\n", __func__); 187 break; 188 case ST_CONTEXT_ERROR_UNKNOWN_FLAG: 189 ERROR("%s: State tracker error: UNKNOWN_FLAG\n", __func__); 190 break; 191 } 192 193 hgl_destroy_st_visual(context->stVisual); 194 FREE(context); 195 return -1; 196 } 197 198 assert(!context->st->st_manager_private); 199 context->st->st_manager_private = (void*)context; 200 201 struct st_context *stContext = (struct st_context*)context->st; 202 203 // Init Gallium3D Post Processing 204 // TODO: no pp filters are enabled yet through postProcessEnable 205 context->postProcess = pp_init(stContext->pipe, context->postProcessEnable, 206 stContext->cso_context); 207 208 context_id contextNext = -1; 209 Lock(); 210 for (context_id i = 0; i < CONTEXT_MAX; i++) { 211 if (fContext[i] == NULL) { 212 fContext[i] = context; 213 contextNext = i; 214 break; 215 } 216 } 217 Unlock(); 218 219 if (contextNext < 0) { 220 ERROR("%s: The next context is invalid... something went wrong!\n", 221 __func__); 222 //st_destroy_context(context->st); 223 FREE(context->stVisual); 224 FREE(context); 225 return -1; 226 } 227 228 TRACE("%s: context #%" B_PRIu64 " is the next available context\n", 229 __func__, contextNext); 230 231 return contextNext; 232 } 233 234 235 void 236 GalliumContext::DestroyContext(context_id contextID) 237 { 238 // fMutex should be locked *before* calling DestoryContext 239 240 // See if context is used 241 if (!fContext[contextID]) 242 return; 243 244 if (fContext[contextID]->st) { 245 fContext[contextID]->st->flush(fContext[contextID]->st, 0, NULL); 246 fContext[contextID]->st->destroy(fContext[contextID]->st); 247 } 248 249 if (fContext[contextID]->postProcess) 250 pp_free(fContext[contextID]->postProcess); 251 252 // Delete state tracker framebuffer objects 253 if (fContext[contextID]->read) 254 delete fContext[contextID]->read; 255 if (fContext[contextID]->draw) 256 delete fContext[contextID]->draw; 257 258 if (fContext[contextID]->stVisual) 259 hgl_destroy_st_visual(fContext[contextID]->stVisual); 260 261 if (fContext[contextID]->manager) 262 hgl_destroy_st_manager(fContext[contextID]->manager); 263 264 FREE(fContext[contextID]); 265 } 266 267 268 status_t 269 GalliumContext::SetCurrentContext(Bitmap *bitmap, context_id contextID) 270 { 271 CALLED(); 272 273 if (contextID < 0 || contextID > CONTEXT_MAX) { 274 ERROR("%s: Invalid context ID range!\n", __func__); 275 return B_ERROR; 276 } 277 278 Lock(); 279 context_id oldContextID = fCurrentContext; 280 struct hgl_context* context = fContext[contextID]; 281 Unlock(); 282 283 if (!context) { 284 ERROR("%s: Invalid context provided (#%" B_PRIu64 ")!\n", 285 __func__, contextID); 286 return B_ERROR; 287 } 288 289 if (!bitmap) { 290 context->api->make_current(context->api, NULL, NULL, NULL); 291 return B_OK; 292 } 293 294 // Everything seems valid, lets set the new context. 295 fCurrentContext = contextID; 296 297 if (oldContextID > 0 && oldContextID != contextID) { 298 fContext[oldContextID]->st->flush(fContext[oldContextID]->st, 299 ST_FLUSH_FRONT, NULL); 300 } 301 302 // We need to lock and unlock framebuffers before accessing them 303 context->api->make_current(context->api, context->st, context->draw->stfbi, 304 context->read->stfbi); 305 306 //if (context->textures[ST_ATTACHMENT_BACK_LEFT] 307 // && context->textures[ST_ATTACHMENT_DEPTH_STENCIL] 308 // && context->postProcess) { 309 // TRACE("Postprocessing textures...\n"); 310 // pp_init_fbos(context->postProcess, 311 // context->textures[ST_ATTACHMENT_BACK_LEFT]->width0, 312 // context->textures[ST_ATTACHMENT_BACK_LEFT]->height0); 313 //} 314 315 context->bitmap = bitmap; 316 //context->st->pipe->priv = context; 317 318 return B_OK; 319 } 320 321 322 status_t 323 GalliumContext::SwapBuffers(context_id contextID) 324 { 325 CALLED(); 326 327 Lock(); 328 struct hgl_context *context = fContext[contextID]; 329 Unlock(); 330 331 if (!context) { 332 ERROR("%s: context not found\n", __func__); 333 return B_ERROR; 334 } 335 336 // TODO: Where did st_notify_swapbuffers go? 337 //st_notify_swapbuffers(context->draw->stfbi); 338 339 context->st->flush(context->st, ST_FLUSH_FRONT, NULL); 340 341 struct st_context *stContext = (struct st_context*)context->st; 342 343 unsigned nColorBuffers = stContext->state.framebuffer.nr_cbufs; 344 for (unsigned i = 0; i < nColorBuffers; i++) { 345 pipe_surface* surface = stContext->state.framebuffer.cbufs[i]; 346 if (!surface) { 347 ERROR("%s: Color buffer %d invalid!\n", __func__, i); 348 continue; 349 } 350 351 TRACE("%s: Flushing color buffer #%d\n", __func__, i); 352 353 // We pass our destination bitmap to flush_fronbuffer which passes it 354 // to the private winsys display call. 355 fScreen->flush_frontbuffer(fScreen, surface->texture, 0, 0, 356 context->bitmap, NULL); 357 } 358 359 #if 0 360 // TODO... should we flush the z stencil buffer? 361 pipe_surface* zSurface = stContext->state.framebuffer.zsbuf; 362 fScreen->flush_frontbuffer(fScreen, zSurface->texture, 0, 0, 363 context->bitmap, NULL); 364 #endif 365 366 return B_OK; 367 } 368 369 370 bool 371 GalliumContext::Validate(uint32 width, uint32 height) 372 { 373 CALLED(); 374 375 if (!fContext[fCurrentContext]) { 376 return false; 377 } 378 379 if (fContext[fCurrentContext]->width != width 380 || fContext[fCurrentContext]->height != height) { 381 Invalidate(width, height); 382 return false; 383 } 384 return true; 385 } 386 387 388 void 389 GalliumContext::Invalidate(uint32 width, uint32 height) 390 { 391 CALLED(); 392 393 assert(fContext[fCurrentContext]); 394 395 // Update st_context dimensions 396 fContext[fCurrentContext]->width = width; 397 fContext[fCurrentContext]->height = height; 398 399 // Is this the best way to invalidate? 400 p_atomic_inc(&fContext[fCurrentContext]->read->stfbi->stamp); 401 p_atomic_inc(&fContext[fCurrentContext]->draw->stfbi->stamp); 402 } 403 404 405 void 406 GalliumContext::Lock() 407 { 408 CALLED(); 409 pipe_mutex_lock(fMutex); 410 } 411 412 413 void 414 GalliumContext::Unlock() 415 { 416 CALLED(); 417 pipe_mutex_unlock(fMutex); 418 } 419 /* vim: set tabstop=4: */ 420