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