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