1848b8605Smrg/*
2848b8605Smrg * Copyright 2012, Haiku, Inc. All Rights Reserved.
3848b8605Smrg * Distributed under the terms of the MIT License.
4848b8605Smrg *
5848b8605Smrg * Authors:
6848b8605Smrg *		Artur Wyszynski, harakash@gmail.com
7848b8605Smrg *		Alexander von Gluck IV, kallisti5@unixzen.com
8848b8605Smrg */
9848b8605Smrg
10848b8605Smrg
11848b8605Smrg#include "GalliumContext.h"
12848b8605Smrg
13b8e80941Smrg#include <stdio.h>
14b8e80941Smrg
15848b8605Smrg#include "GLView.h"
16848b8605Smrg
17848b8605Smrg#include "bitmap_wrapper.h"
18b8e80941Smrg
19848b8605Smrg#include "glapi/glapi.h"
20848b8605Smrg#include "pipe/p_format.h"
21b8e80941Smrg//#include "state_tracker/st_cb_fbo.h"
22b8e80941Smrg//#include "state_tracker/st_cb_flush.h"
23848b8605Smrg#include "state_tracker/st_context.h"
24848b8605Smrg#include "state_tracker/st_gl_api.h"
25848b8605Smrg#include "state_tracker/sw_winsys.h"
26b8e80941Smrg#include "sw/hgl/hgl_sw_winsys.h"
27b8e80941Smrg#include "util/u_atomic.h"
28848b8605Smrg#include "util/u_memory.h"
29848b8605Smrg
30848b8605Smrg#include "target-helpers/inline_sw_helper.h"
31848b8605Smrg#include "target-helpers/inline_debug_helper.h"
32848b8605Smrg
33848b8605Smrg
34848b8605Smrg#ifdef DEBUG
35848b8605Smrg#	define TRACE(x...) printf("GalliumContext: " x)
36848b8605Smrg#	define CALLED() TRACE("CALLED: %s\n", __PRETTY_FUNCTION__)
37848b8605Smrg#else
38848b8605Smrg#	define TRACE(x...)
39848b8605Smrg#	define CALLED()
40848b8605Smrg#endif
41848b8605Smrg#define ERROR(x...) printf("GalliumContext: " x)
42848b8605Smrg
43848b8605Smrg
44848b8605SmrgGalliumContext::GalliumContext(ulong options)
45848b8605Smrg	:
46848b8605Smrg	fOptions(options),
47848b8605Smrg	fScreen(NULL),
48848b8605Smrg	fCurrentContext(0)
49848b8605Smrg{
50848b8605Smrg	CALLED();
51848b8605Smrg
52848b8605Smrg	// Make all contexts a known value
53848b8605Smrg	for (context_id i = 0; i < CONTEXT_MAX; i++)
54848b8605Smrg		fContext[i] = NULL;
55848b8605Smrg
56848b8605Smrg	CreateScreen();
57848b8605Smrg
58b8e80941Smrg	(void) mtx_init(&fMutex, mtx_plain);
59848b8605Smrg}
60848b8605Smrg
61848b8605Smrg
62848b8605SmrgGalliumContext::~GalliumContext()
63848b8605Smrg{
64848b8605Smrg	CALLED();
65848b8605Smrg
66848b8605Smrg	// Destroy our contexts
67848b8605Smrg	Lock();
68848b8605Smrg	for (context_id i = 0; i < CONTEXT_MAX; i++)
69848b8605Smrg		DestroyContext(i);
70848b8605Smrg	Unlock();
71848b8605Smrg
72b8e80941Smrg	mtx_destroy(&fMutex);
73848b8605Smrg
74848b8605Smrg	// TODO: Destroy fScreen
75848b8605Smrg}
76848b8605Smrg
77848b8605Smrg
78848b8605Smrgstatus_t
79848b8605SmrgGalliumContext::CreateScreen()
80848b8605Smrg{
81848b8605Smrg	CALLED();
82848b8605Smrg
83848b8605Smrg	// Allocate winsys and attach callback hooks
84848b8605Smrg	struct sw_winsys* winsys = hgl_create_sw_winsys();
85848b8605Smrg
86848b8605Smrg	if (!winsys) {
87848b8605Smrg		ERROR("%s: Couldn't allocate sw_winsys!\n", __func__);
88848b8605Smrg		return B_ERROR;
89848b8605Smrg	}
90848b8605Smrg
91848b8605Smrg	fScreen = sw_screen_create(winsys);
92848b8605Smrg
93848b8605Smrg	if (fScreen == NULL) {
94848b8605Smrg		ERROR("%s: Couldn't create screen!\n", __FUNCTION__);
95848b8605Smrg		FREE(winsys);
96848b8605Smrg		return B_ERROR;
97848b8605Smrg	}
98848b8605Smrg
99848b8605Smrg	debug_screen_wrap(fScreen);
100848b8605Smrg
101848b8605Smrg	const char* driverName = fScreen->get_name(fScreen);
102848b8605Smrg	ERROR("%s: Using %s driver.\n", __func__, driverName);
103848b8605Smrg
104848b8605Smrg	return B_OK;
105848b8605Smrg}
106848b8605Smrg
107848b8605Smrg
108848b8605Smrgcontext_id
109848b8605SmrgGalliumContext::CreateContext(Bitmap *bitmap)
110848b8605Smrg{
111848b8605Smrg	CALLED();
112848b8605Smrg
113848b8605Smrg	struct hgl_context* context = CALLOC_STRUCT(hgl_context);
114848b8605Smrg
115848b8605Smrg	if (!context) {
116848b8605Smrg		ERROR("%s: Couldn't create pipe context!\n", __FUNCTION__);
117848b8605Smrg		return 0;
118848b8605Smrg	}
119848b8605Smrg
120848b8605Smrg	// Set up the initial things our context needs
121848b8605Smrg	context->bitmap = bitmap;
122848b8605Smrg	context->colorSpace = get_bitmap_color_space(bitmap);
123b8e80941Smrg	context->screen = fScreen;
124848b8605Smrg	context->draw = NULL;
125848b8605Smrg	context->read = NULL;
126848b8605Smrg	context->st = NULL;
127848b8605Smrg
128b8e80941Smrg	// Create st_gl_api
129b8e80941Smrg	context->api = hgl_create_st_api();
130848b8605Smrg	if (!context->api) {
131848b8605Smrg		ERROR("%s: Couldn't obtain Mesa state tracker API!\n", __func__);
132848b8605Smrg		return -1;
133848b8605Smrg	}
134848b8605Smrg
135b8e80941Smrg	// Create state_tracker manager
136b8e80941Smrg	context->manager = hgl_create_st_manager(context);
137848b8605Smrg
138b8e80941Smrg	// Create state tracker visual
139b8e80941Smrg	context->stVisual = hgl_create_st_visual(fOptions);
140848b8605Smrg
141b8e80941Smrg	// Create state tracker framebuffers
142b8e80941Smrg	context->draw = hgl_create_st_framebuffer(context);
143b8e80941Smrg	context->read = hgl_create_st_framebuffer(context);
144848b8605Smrg
145848b8605Smrg	if (!context->draw || !context->read) {
146848b8605Smrg		ERROR("%s: Problem allocating framebuffer!\n", __func__);
147b8e80941Smrg		FREE(context->stVisual);
148848b8605Smrg		return -1;
149848b8605Smrg	}
150848b8605Smrg
151848b8605Smrg	// Build state tracker attributes
152848b8605Smrg	struct st_context_attribs attribs;
153848b8605Smrg	memset(&attribs, 0, sizeof(attribs));
154848b8605Smrg	attribs.options.force_glsl_extensions_warn = false;
155848b8605Smrg	attribs.profile = ST_PROFILE_DEFAULT;
156848b8605Smrg	attribs.visual = *context->stVisual;
157848b8605Smrg	attribs.major = 1;
158848b8605Smrg	attribs.minor = 0;
159848b8605Smrg	//attribs.flags |= ST_CONTEXT_FLAG_DEBUG;
160848b8605Smrg
161848b8605Smrg	// Create context using state tracker api call
162848b8605Smrg	enum st_context_error result;
163b8e80941Smrg	context->st = context->api->create_context(context->api, context->manager,
164b8e80941Smrg		&attribs, &result, context->st);
165848b8605Smrg
166848b8605Smrg	if (!context->st) {
167848b8605Smrg		ERROR("%s: Couldn't create mesa state tracker context!\n",
168848b8605Smrg			__func__);
169848b8605Smrg		switch (result) {
170848b8605Smrg			case ST_CONTEXT_SUCCESS:
171848b8605Smrg				ERROR("%s: State tracker error: SUCCESS?\n", __func__);
172848b8605Smrg				break;
173848b8605Smrg			case ST_CONTEXT_ERROR_NO_MEMORY:
174848b8605Smrg				ERROR("%s: State tracker error: NO_MEMORY\n", __func__);
175848b8605Smrg				break;
176848b8605Smrg			case ST_CONTEXT_ERROR_BAD_API:
177848b8605Smrg				ERROR("%s: State tracker error: BAD_API\n", __func__);
178848b8605Smrg				break;
179848b8605Smrg			case ST_CONTEXT_ERROR_BAD_VERSION:
180848b8605Smrg				ERROR("%s: State tracker error: BAD_VERSION\n", __func__);
181848b8605Smrg				break;
182848b8605Smrg			case ST_CONTEXT_ERROR_BAD_FLAG:
183848b8605Smrg				ERROR("%s: State tracker error: BAD_FLAG\n", __func__);
184848b8605Smrg				break;
185848b8605Smrg			case ST_CONTEXT_ERROR_UNKNOWN_ATTRIBUTE:
186848b8605Smrg				ERROR("%s: State tracker error: BAD_ATTRIBUTE\n", __func__);
187848b8605Smrg				break;
188848b8605Smrg			case ST_CONTEXT_ERROR_UNKNOWN_FLAG:
189848b8605Smrg				ERROR("%s: State tracker error: UNKNOWN_FLAG\n", __func__);
190848b8605Smrg				break;
191848b8605Smrg		}
192848b8605Smrg
193b8e80941Smrg		hgl_destroy_st_visual(context->stVisual);
194848b8605Smrg		FREE(context);
195848b8605Smrg		return -1;
196848b8605Smrg	}
197848b8605Smrg
198848b8605Smrg	assert(!context->st->st_manager_private);
199848b8605Smrg	context->st->st_manager_private = (void*)context;
200848b8605Smrg
201848b8605Smrg	struct st_context *stContext = (struct st_context*)context->st;
202848b8605Smrg
203848b8605Smrg	// Init Gallium3D Post Processing
204848b8605Smrg	// TODO: no pp filters are enabled yet through postProcessEnable
205848b8605Smrg	context->postProcess = pp_init(stContext->pipe, context->postProcessEnable,
206848b8605Smrg		stContext->cso_context);
207848b8605Smrg
208848b8605Smrg	context_id contextNext = -1;
209848b8605Smrg	Lock();
210848b8605Smrg	for (context_id i = 0; i < CONTEXT_MAX; i++) {
211848b8605Smrg		if (fContext[i] == NULL) {
212848b8605Smrg			fContext[i] = context;
213848b8605Smrg			contextNext = i;
214848b8605Smrg			break;
215848b8605Smrg		}
216848b8605Smrg	}
217848b8605Smrg	Unlock();
218848b8605Smrg
219848b8605Smrg	if (contextNext < 0) {
220848b8605Smrg		ERROR("%s: The next context is invalid... something went wrong!\n",
221848b8605Smrg			__func__);
222848b8605Smrg		//st_destroy_context(context->st);
223b8e80941Smrg		FREE(context->stVisual);
224848b8605Smrg		FREE(context);
225848b8605Smrg		return -1;
226848b8605Smrg	}
227848b8605Smrg
228848b8605Smrg	TRACE("%s: context #%" B_PRIu64 " is the next available context\n",
229848b8605Smrg		__func__, contextNext);
230848b8605Smrg
231848b8605Smrg	return contextNext;
232848b8605Smrg}
233848b8605Smrg
234848b8605Smrg
235848b8605Smrgvoid
236848b8605SmrgGalliumContext::DestroyContext(context_id contextID)
237848b8605Smrg{
238848b8605Smrg	// fMutex should be locked *before* calling DestoryContext
239848b8605Smrg
240848b8605Smrg	// See if context is used
241848b8605Smrg	if (!fContext[contextID])
242848b8605Smrg		return;
243848b8605Smrg
244848b8605Smrg	if (fContext[contextID]->st) {
245848b8605Smrg		fContext[contextID]->st->flush(fContext[contextID]->st, 0, NULL);
246848b8605Smrg		fContext[contextID]->st->destroy(fContext[contextID]->st);
247848b8605Smrg	}
248848b8605Smrg
249848b8605Smrg	if (fContext[contextID]->postProcess)
250848b8605Smrg		pp_free(fContext[contextID]->postProcess);
251848b8605Smrg
252b8e80941Smrg	// Delete state tracker framebuffer objects
253848b8605Smrg	if (fContext[contextID]->read)
254848b8605Smrg		delete fContext[contextID]->read;
255848b8605Smrg	if (fContext[contextID]->draw)
256848b8605Smrg		delete fContext[contextID]->draw;
257848b8605Smrg
258848b8605Smrg	if (fContext[contextID]->stVisual)
259b8e80941Smrg		hgl_destroy_st_visual(fContext[contextID]->stVisual);
260848b8605Smrg
261848b8605Smrg	if (fContext[contextID]->manager)
262b8e80941Smrg		hgl_destroy_st_manager(fContext[contextID]->manager);
263848b8605Smrg
264848b8605Smrg	FREE(fContext[contextID]);
265848b8605Smrg}
266848b8605Smrg
267848b8605Smrg
268848b8605Smrgstatus_t
269848b8605SmrgGalliumContext::SetCurrentContext(Bitmap *bitmap, context_id contextID)
270848b8605Smrg{
271848b8605Smrg	CALLED();
272848b8605Smrg
273848b8605Smrg	if (contextID < 0 || contextID > CONTEXT_MAX) {
274848b8605Smrg		ERROR("%s: Invalid context ID range!\n", __func__);
275848b8605Smrg		return B_ERROR;
276848b8605Smrg	}
277848b8605Smrg
278848b8605Smrg	Lock();
279848b8605Smrg	context_id oldContextID = fCurrentContext;
280848b8605Smrg	struct hgl_context* context = fContext[contextID];
281848b8605Smrg	Unlock();
282848b8605Smrg
283848b8605Smrg	if (!context) {
284848b8605Smrg		ERROR("%s: Invalid context provided (#%" B_PRIu64 ")!\n",
285848b8605Smrg			__func__, contextID);
286848b8605Smrg		return B_ERROR;
287848b8605Smrg	}
288848b8605Smrg
289848b8605Smrg	if (!bitmap) {
290b8e80941Smrg		context->api->make_current(context->api, NULL, NULL, NULL);
291848b8605Smrg		return B_OK;
292848b8605Smrg	}
293848b8605Smrg
294848b8605Smrg	// Everything seems valid, lets set the new context.
295848b8605Smrg	fCurrentContext = contextID;
296848b8605Smrg
297848b8605Smrg	if (oldContextID > 0 && oldContextID != contextID) {
298848b8605Smrg		fContext[oldContextID]->st->flush(fContext[oldContextID]->st,
299848b8605Smrg			ST_FLUSH_FRONT, NULL);
300848b8605Smrg	}
301848b8605Smrg
302848b8605Smrg	// We need to lock and unlock framebuffers before accessing them
303b8e80941Smrg	context->api->make_current(context->api, context->st, context->draw->stfbi,
304b8e80941Smrg		context->read->stfbi);
305b8e80941Smrg
306b8e80941Smrg	//if (context->textures[ST_ATTACHMENT_BACK_LEFT]
307b8e80941Smrg	//	&& context->textures[ST_ATTACHMENT_DEPTH_STENCIL]
308b8e80941Smrg	//	&& context->postProcess) {
309b8e80941Smrg	//	TRACE("Postprocessing textures...\n");
310b8e80941Smrg	//	pp_init_fbos(context->postProcess,
311b8e80941Smrg	//		context->textures[ST_ATTACHMENT_BACK_LEFT]->width0,
312b8e80941Smrg	//		context->textures[ST_ATTACHMENT_BACK_LEFT]->height0);
313b8e80941Smrg	//}
314848b8605Smrg
315848b8605Smrg	context->bitmap = bitmap;
316848b8605Smrg	//context->st->pipe->priv = context;
317848b8605Smrg
318848b8605Smrg	return B_OK;
319848b8605Smrg}
320848b8605Smrg
321848b8605Smrg
322848b8605Smrgstatus_t
323848b8605SmrgGalliumContext::SwapBuffers(context_id contextID)
324848b8605Smrg{
325848b8605Smrg	CALLED();
326848b8605Smrg
327848b8605Smrg	Lock();
328848b8605Smrg	struct hgl_context *context = fContext[contextID];
329848b8605Smrg	Unlock();
330848b8605Smrg
331848b8605Smrg	if (!context) {
332848b8605Smrg		ERROR("%s: context not found\n", __func__);
333848b8605Smrg		return B_ERROR;
334848b8605Smrg	}
335848b8605Smrg
336848b8605Smrg	// TODO: Where did st_notify_swapbuffers go?
337b8e80941Smrg	//st_notify_swapbuffers(context->draw->stfbi);
338848b8605Smrg
339848b8605Smrg	context->st->flush(context->st, ST_FLUSH_FRONT, NULL);
340848b8605Smrg
341848b8605Smrg	struct st_context *stContext = (struct st_context*)context->st;
342848b8605Smrg
343848b8605Smrg	unsigned nColorBuffers = stContext->state.framebuffer.nr_cbufs;
344848b8605Smrg	for (unsigned i = 0; i < nColorBuffers; i++) {
345848b8605Smrg		pipe_surface* surface = stContext->state.framebuffer.cbufs[i];
346848b8605Smrg		if (!surface) {
347848b8605Smrg			ERROR("%s: Color buffer %d invalid!\n", __func__, i);
348848b8605Smrg			continue;
349848b8605Smrg		}
350848b8605Smrg
351848b8605Smrg		TRACE("%s: Flushing color buffer #%d\n", __func__, i);
352848b8605Smrg
353848b8605Smrg		// We pass our destination bitmap to flush_fronbuffer which passes it
354848b8605Smrg		// to the private winsys display call.
355848b8605Smrg		fScreen->flush_frontbuffer(fScreen, surface->texture, 0, 0,
356848b8605Smrg			context->bitmap, NULL);
357848b8605Smrg	}
358848b8605Smrg
359848b8605Smrg	#if 0
360848b8605Smrg	// TODO... should we flush the z stencil buffer?
361848b8605Smrg	pipe_surface* zSurface = stContext->state.framebuffer.zsbuf;
362848b8605Smrg	fScreen->flush_frontbuffer(fScreen, zSurface->texture, 0, 0,
363848b8605Smrg		context->bitmap, NULL);
364848b8605Smrg	#endif
365848b8605Smrg
366848b8605Smrg	return B_OK;
367848b8605Smrg}
368848b8605Smrg
369848b8605Smrg
370b8e80941Smrgbool
371b8e80941SmrgGalliumContext::Validate(uint32 width, uint32 height)
372848b8605Smrg{
373848b8605Smrg	CALLED();
374b8e80941Smrg
375b8e80941Smrg	if (!fContext[fCurrentContext]) {
376b8e80941Smrg		return false;
377b8e80941Smrg	}
378b8e80941Smrg
379b8e80941Smrg	if (fContext[fCurrentContext]->width != width
380b8e80941Smrg		|| fContext[fCurrentContext]->height != height) {
381b8e80941Smrg		Invalidate(width, height);
382b8e80941Smrg		return false;
383848b8605Smrg	}
384b8e80941Smrg	return true;
385b8e80941Smrg}
386b8e80941Smrg
387b8e80941Smrg
388b8e80941Smrgvoid
389b8e80941SmrgGalliumContext::Invalidate(uint32 width, uint32 height)
390b8e80941Smrg{
391b8e80941Smrg	CALLED();
392b8e80941Smrg
393b8e80941Smrg	assert(fContext[fCurrentContext]);
394b8e80941Smrg
395b8e80941Smrg	// Update st_context dimensions
396b8e80941Smrg	fContext[fCurrentContext]->width = width;
397b8e80941Smrg	fContext[fCurrentContext]->height = height;
398b8e80941Smrg
399b8e80941Smrg	// Is this the best way to invalidate?
400b8e80941Smrg	p_atomic_inc(&fContext[fCurrentContext]->read->stfbi->stamp);
401b8e80941Smrg	p_atomic_inc(&fContext[fCurrentContext]->draw->stfbi->stamp);
402848b8605Smrg}
403848b8605Smrg
404848b8605Smrg
405848b8605Smrgvoid
406848b8605SmrgGalliumContext::Lock()
407848b8605Smrg{
408848b8605Smrg	CALLED();
409b8e80941Smrg	mtx_lock(&fMutex);
410848b8605Smrg}
411848b8605Smrg
412848b8605Smrg
413848b8605Smrgvoid
414848b8605SmrgGalliumContext::Unlock()
415848b8605Smrg{
416848b8605Smrg	CALLED();
417b8e80941Smrg	mtx_unlock(&fMutex);
418848b8605Smrg}
419848b8605Smrg/* vim: set tabstop=4: */
420