Path: blob/21.2-virgl/src/gallium/targets/haiku-softpipe/GalliumContext.cpp
4565 views
/*1* Copyright 2012, Haiku, Inc. All Rights Reserved.2* Distributed under the terms of the MIT License.3*4* Authors:5* Artur Wyszynski, [email protected]6* Alexander von Gluck IV, [email protected]7*/8910#include "GalliumContext.h"1112#include <stdio.h>13#include <algorithm>1415#include "GLView.h"1617#include "bitmap_wrapper.h"1819#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 "frontend/sw_winsys.h"26#include "sw/hgl/hgl_sw_winsys.h"27#include "util/u_atomic.h"28#include "util/u_memory.h"29#include "util/u_framebuffer.h"3031#include "target-helpers/inline_sw_helper.h"32#include "target-helpers/inline_debug_helper.h"333435#ifdef DEBUG36# define TRACE(x...) printf("GalliumContext: " x)37# define CALLED() TRACE("CALLED: %s\n", __PRETTY_FUNCTION__)38#else39# define TRACE(x...)40# define CALLED()41#endif42#define ERROR(x...) printf("GalliumContext: " x)4344int32 GalliumContext::fDisplayRefCount = 0;45hgl_display* GalliumContext::fDisplay = NULL;4647GalliumContext::GalliumContext(ulong options)48:49fOptions(options),50fCurrentContext(0)51{52CALLED();5354// Make all contexts a known value55for (context_id i = 0; i < CONTEXT_MAX; i++)56fContext[i] = NULL;5758CreateDisplay();5960(void) mtx_init(&fMutex, mtx_plain);61}626364GalliumContext::~GalliumContext()65{66CALLED();6768// Destroy our contexts69Lock();70for (context_id i = 0; i < CONTEXT_MAX; i++)71DestroyContext(i);72Unlock();7374DestroyDisplay();7576mtx_destroy(&fMutex);77}787980status_t81GalliumContext::CreateDisplay()82{83CALLED();8485if (atomic_add(&fDisplayRefCount, 1) > 0)86return B_OK;8788// Allocate winsys and attach callback hooks89struct sw_winsys* winsys = hgl_create_sw_winsys();9091if (!winsys) {92ERROR("%s: Couldn't allocate sw_winsys!\n", __func__);93return B_ERROR;94}9596struct pipe_screen* screen = sw_screen_create(winsys);9798if (screen == NULL) {99ERROR("%s: Couldn't create screen!\n", __FUNCTION__);100winsys->destroy(winsys);101return B_ERROR;102}103104debug_screen_wrap(screen);105106const char* driverName = screen->get_name(screen);107ERROR("%s: Using %s driver.\n", __func__, driverName);108109fDisplay = hgl_create_display(screen);110111if (fDisplay == NULL) {112ERROR("%s: Couldn't create display!\n", __FUNCTION__);113screen->destroy(screen); // will also destroy winsys114return B_ERROR;115}116117return B_OK;118}119120121void122GalliumContext::DestroyDisplay()123{124if (atomic_add(&fDisplayRefCount, -1) > 1)125return;126127if (fDisplay != NULL) {128struct pipe_screen* screen = fDisplay->manager->screen;129hgl_destroy_display(fDisplay); fDisplay = NULL;130screen->destroy(screen); // destroy will deallocate object131}132}133134135context_id136GalliumContext::CreateContext(HGLWinsysContext *wsContext)137{138CALLED();139140struct hgl_context* context = CALLOC_STRUCT(hgl_context);141142if (!context) {143ERROR("%s: Couldn't create pipe context!\n", __FUNCTION__);144return 0;145}146147// Set up the initial things our context needs148context->display = fDisplay;149150// Create state tracker visual151context->stVisual = hgl_create_st_visual(fOptions);152153// Create state tracker framebuffers154context->buffer = hgl_create_st_framebuffer(context, wsContext);155156if (!context->buffer) {157ERROR("%s: Problem allocating framebuffer!\n", __func__);158FREE(context->stVisual);159return -1;160}161162// Build state tracker attributes163struct st_context_attribs attribs;164memset(&attribs, 0, sizeof(attribs));165attribs.options.force_glsl_extensions_warn = false;166attribs.profile = ST_PROFILE_DEFAULT;167attribs.visual = *context->stVisual;168attribs.major = 1;169attribs.minor = 0;170//attribs.flags |= ST_CONTEXT_FLAG_DEBUG;171172struct st_context_iface* shared = NULL;173174if (fOptions & BGL_SHARE_CONTEXT) {175shared = fDisplay->api->get_current(fDisplay->api);176TRACE("shared context: %p\n", shared);177}178179// Create context using state tracker api call180enum st_context_error result;181context->st = fDisplay->api->create_context(fDisplay->api, fDisplay->manager,182&attribs, &result, shared);183184if (!context->st) {185ERROR("%s: Couldn't create mesa state tracker context!\n",186__func__);187switch (result) {188case ST_CONTEXT_SUCCESS:189ERROR("%s: State tracker error: SUCCESS?\n", __func__);190break;191case ST_CONTEXT_ERROR_NO_MEMORY:192ERROR("%s: State tracker error: NO_MEMORY\n", __func__);193break;194case ST_CONTEXT_ERROR_BAD_API:195ERROR("%s: State tracker error: BAD_API\n", __func__);196break;197case ST_CONTEXT_ERROR_BAD_VERSION:198ERROR("%s: State tracker error: BAD_VERSION\n", __func__);199break;200case ST_CONTEXT_ERROR_BAD_FLAG:201ERROR("%s: State tracker error: BAD_FLAG\n", __func__);202break;203case ST_CONTEXT_ERROR_UNKNOWN_ATTRIBUTE:204ERROR("%s: State tracker error: BAD_ATTRIBUTE\n", __func__);205break;206case ST_CONTEXT_ERROR_UNKNOWN_FLAG:207ERROR("%s: State tracker error: UNKNOWN_FLAG\n", __func__);208break;209}210211hgl_destroy_st_visual(context->stVisual);212FREE(context);213return -1;214}215216assert(!context->st->st_manager_private);217context->st->st_manager_private = (void*)context;218219struct st_context *stContext = (struct st_context*)context->st;220221// Init Gallium3D Post Processing222// TODO: no pp filters are enabled yet through postProcessEnable223context->postProcess = pp_init(stContext->pipe, context->postProcessEnable,224stContext->cso_context, &stContext->iface);225226context_id contextNext = -1;227Lock();228for (context_id i = 0; i < CONTEXT_MAX; i++) {229if (fContext[i] == NULL) {230fContext[i] = context;231contextNext = i;232break;233}234}235Unlock();236237if (contextNext < 0) {238ERROR("%s: The next context is invalid... something went wrong!\n",239__func__);240//st_destroy_context(context->st);241FREE(context->stVisual);242FREE(context);243return -1;244}245246TRACE("%s: context #%" B_PRIu64 " is the next available context\n",247__func__, contextNext);248249return contextNext;250}251252253void254GalliumContext::DestroyContext(context_id contextID)255{256// fMutex should be locked *before* calling DestoryContext257258// See if context is used259if (!fContext[contextID])260return;261262if (fContext[contextID]->st) {263fContext[contextID]->st->flush(fContext[contextID]->st, 0, NULL, NULL, NULL);264fContext[contextID]->st->destroy(fContext[contextID]->st);265}266267if (fContext[contextID]->postProcess)268pp_free(fContext[contextID]->postProcess);269270// Delete state tracker framebuffer objects271if (fContext[contextID]->buffer)272hgl_destroy_st_framebuffer(fContext[contextID]->buffer);273274if (fContext[contextID]->stVisual)275hgl_destroy_st_visual(fContext[contextID]->stVisual);276277FREE(fContext[contextID]);278}279280281status_t282GalliumContext::SetCurrentContext(bool set, context_id contextID)283{284CALLED();285286if (contextID < 0 || contextID > CONTEXT_MAX) {287ERROR("%s: Invalid context ID range!\n", __func__);288return B_ERROR;289}290291Lock();292context_id oldContextID = fCurrentContext;293struct hgl_context* context = fContext[contextID];294295if (!context) {296ERROR("%s: Invalid context provided (#%" B_PRIu64 ")!\n",297__func__, contextID);298Unlock();299return B_ERROR;300}301302if (!set) {303fDisplay->api->make_current(fDisplay->api, NULL, NULL, NULL);304Unlock();305return B_OK;306}307308// Everything seems valid, lets set the new context.309fCurrentContext = contextID;310311if (oldContextID > 0 && oldContextID != contextID) {312fContext[oldContextID]->st->flush(fContext[oldContextID]->st,313ST_FLUSH_FRONT, NULL, NULL, NULL);314}315316// We need to lock and unlock framebuffers before accessing them317fDisplay->api->make_current(fDisplay->api, context->st, context->buffer->stfbi,318context->buffer->stfbi);319Unlock();320321return B_OK;322}323324325status_t326GalliumContext::SwapBuffers(context_id contextID)327{328CALLED();329330Lock();331struct hgl_context* context = fContext[contextID];332333if (!context) {334ERROR("%s: context not found\n", __func__);335Unlock();336return B_ERROR;337}338339// will flush front buffer if no double buffering is used340context->st->flush(context->st, ST_FLUSH_FRONT, NULL, NULL, NULL);341342struct hgl_buffer* buffer = context->buffer;343344// flush back buffer and swap buffers if double buffering is used345if (buffer->textures[ST_ATTACHMENT_BACK_LEFT] != NULL) {346buffer->screen->flush_frontbuffer(buffer->screen, NULL, buffer->textures[ST_ATTACHMENT_BACK_LEFT],3470, 0, buffer->winsysContext, NULL);348std::swap(buffer->textures[ST_ATTACHMENT_FRONT_LEFT], buffer->textures[ST_ATTACHMENT_BACK_LEFT]);349p_atomic_inc(&buffer->stfbi->stamp);350}351352Unlock();353return B_OK;354}355356357void358GalliumContext::Draw(context_id contextID, BRect updateRect)359{360struct hgl_context *context = fContext[contextID];361362if (!context) {363ERROR("%s: context not found\n", __func__);364return;365}366367struct hgl_buffer* buffer = context->buffer;368369if (buffer->textures[ST_ATTACHMENT_FRONT_LEFT] == NULL)370return;371372buffer->screen->flush_frontbuffer(buffer->screen, NULL, buffer->textures[ST_ATTACHMENT_FRONT_LEFT],3730, 0, buffer->winsysContext, NULL);374}375376377bool378GalliumContext::Validate(uint32 width, uint32 height)379{380CALLED();381382if (!fContext[fCurrentContext])383return false;384385if (fContext[fCurrentContext]->width != width + 1386|| fContext[fCurrentContext]->height != height + 1) {387Invalidate(width, height);388return false;389}390return true;391}392393394void395GalliumContext::Invalidate(uint32 width, uint32 height)396{397CALLED();398399assert(fContext[fCurrentContext]);400401// Update st_context dimensions402fContext[fCurrentContext]->width = width + 1;403fContext[fCurrentContext]->height = height + 1;404405// Is this the best way to invalidate?406p_atomic_inc(&fContext[fCurrentContext]->buffer->stfbi->stamp);407}408409410void411GalliumContext::Lock()412{413CALLED();414mtx_lock(&fMutex);415}416417418void419GalliumContext::Unlock()420{421CALLED();422mtx_unlock(&fMutex);423}424/* vim: set tabstop=4: */425426427