GalliumContext.cpp revision 01e04c3f
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
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
44GalliumContext::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	(void) mtx_init(&fMutex, mtx_plain);
59}
60
61
62GalliumContext::~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	mtx_destroy(&fMutex);
73
74	// TODO: Destroy fScreen
75}
76
77
78status_t
79GalliumContext::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
108context_id
109GalliumContext::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
235void
236GalliumContext::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
268status_t
269GalliumContext::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
322status_t
323GalliumContext::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
370bool
371GalliumContext::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
388void
389GalliumContext::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
405void
406GalliumContext::Lock()
407{
408	CALLED();
409	mtx_lock(&fMutex);
410}
411
412
413void
414GalliumContext::Unlock()
415{
416	CALLED();
417	mtx_unlock(&fMutex);
418}
419/* vim: set tabstop=4: */
420