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