Home | History | Annotate | Download | only in haiku-softpipe
      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