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