• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GalliumContext(ulong options)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 	(void) mtx_init(&fMutex, mtx_plain);
59 }
60 
61 
~GalliumContext()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 	mtx_destroy(&fMutex);
73 
74 	// TODO: Destroy fScreen
75 }
76 
77 
78 status_t
CreateScreen()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
CreateContext(Bitmap * bitmap)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
DestroyContext(context_id contextID)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
SetCurrentContext(Bitmap * bitmap,context_id contextID)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
SwapBuffers(context_id contextID)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
Validate(uint32 width,uint32 height)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
Invalidate(uint32 width,uint32 height)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
Lock()406 GalliumContext::Lock()
407 {
408 	CALLED();
409 	mtx_lock(&fMutex);
410 }
411 
412 
413 void
Unlock()414 GalliumContext::Unlock()
415 {
416 	CALLED();
417 	mtx_unlock(&fMutex);
418 }
419 /* vim: set tabstop=4: */
420