haiku: Fix llvmpipe and clean up softpipe tracing
[mesa.git] / src / gallium / targets / haiku-softpipe / GalliumContext.cpp
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 "GLView.h"
14
15 #include "bitmap_wrapper.h"
16 extern "C" {
17 #include "glapi/glapi.h"
18 #include "main/context.h"
19 #include "main/framebuffer.h"
20 #include "main/renderbuffer.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 "state_tracker/st_manager.h"
27 #include "state_tracker/sw_winsys.h"
28 #include "hgl_sw_winsys.h"
29
30 #include "target-helpers/inline_sw_helper.h"
31 #include "target-helpers/inline_debug_helper.h"
32 }
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
45 static void
46 hgl_viewport(struct gl_context* glContext, GLint x, GLint y,
47 GLsizei width, GLsizei height)
48 {
49 TRACE("%s(glContext: %p, x: %d, y: %d, w: %d, h: %d\n", __func__,
50 glContext, x, y, width, height);
51
52 struct gl_framebuffer *draw = glContext->WinSysDrawBuffer;
53 struct gl_framebuffer *read = glContext->WinSysReadBuffer;
54
55 // TODO: SLOW! We need to check for changes in bitmap vs gl_framebuffer
56 // size before doing a _mesa_resize_framebuffer.
57 if (draw)
58 _mesa_resize_framebuffer(glContext, draw, width, height);
59 if (read)
60 _mesa_resize_framebuffer(glContext, read, width, height);
61 }
62
63
64 static st_visual*
65 hgl_fill_st_visual(gl_config* glVisual)
66 {
67 struct st_visual* stVisual = CALLOC_STRUCT(st_visual);
68 if (!stVisual) {
69 ERROR("%s: Couldn't allocate st_visual\n", __func__);
70 return NULL;
71 }
72
73 // Determine color format
74 if (glVisual->redBits == 8) {
75 if (glVisual->alphaBits == 8)
76 stVisual->color_format = PIPE_FORMAT_B8G8R8A8_UNORM;
77 else
78 stVisual->color_format = PIPE_FORMAT_B8G8R8X8_UNORM;
79 } else {
80 stVisual->color_format = PIPE_FORMAT_B5G6R5_UNORM;
81 }
82
83 // Determine depth stencil format
84 switch (glVisual->depthBits) {
85 default:
86 case 0:
87 stVisual->depth_stencil_format = PIPE_FORMAT_NONE;
88 break;
89 case 16:
90 stVisual->depth_stencil_format = PIPE_FORMAT_Z16_UNORM;
91 break;
92 case 24:
93 if (glVisual->stencilBits == 0) {
94 stVisual->depth_stencil_format = PIPE_FORMAT_Z24X8_UNORM;
95 // or PIPE_FORMAT_X8Z24_UNORM?
96 } else {
97 stVisual->depth_stencil_format = PIPE_FORMAT_Z24_UNORM_S8_UINT;
98 // or PIPE_FORMAT_S8_UINT_Z24_UNORM?
99 }
100 break;
101 case 32:
102 stVisual->depth_stencil_format = PIPE_FORMAT_Z32_UNORM;
103 break;
104 }
105
106 stVisual->accum_format = (glVisual->haveAccumBuffer)
107 ? PIPE_FORMAT_R16G16B16A16_SNORM : PIPE_FORMAT_NONE;
108
109 stVisual->buffer_mask |= ST_ATTACHMENT_FRONT_LEFT_MASK;
110 stVisual->render_buffer = ST_ATTACHMENT_FRONT_LEFT;
111 if (glVisual->doubleBufferMode) {
112 stVisual->buffer_mask |= ST_ATTACHMENT_BACK_LEFT_MASK;
113 stVisual->render_buffer = ST_ATTACHMENT_BACK_LEFT;
114 }
115
116 if (glVisual->stereoMode) {
117 stVisual->buffer_mask |= ST_ATTACHMENT_FRONT_RIGHT_MASK;
118 if (glVisual->doubleBufferMode)
119 stVisual->buffer_mask |= ST_ATTACHMENT_BACK_RIGHT_MASK;
120 }
121
122 if (glVisual->haveDepthBuffer || glVisual->haveStencilBuffer)
123 stVisual->buffer_mask |= ST_ATTACHMENT_DEPTH_STENCIL_MASK;
124
125 return stVisual;
126 }
127
128
129 static INLINE unsigned
130 round_up(unsigned n, unsigned multiple)
131 {
132 return (n + multiple - 1) & ~(multiple - 1);
133 }
134
135
136 static int
137 hook_stm_get_param(struct st_manager *smapi, enum st_manager_param param)
138 {
139 CALLED();
140
141 switch (param) {
142 case ST_MANAGER_BROKEN_INVALIDATE:
143 TRACE("%s: TODO: How should we handle BROKEN_INVALIDATE calls?\n",
144 __func__);
145 // For now we force validation of the framebuffer.
146 return 1;
147 }
148
149 return 0;
150 }
151
152
153 GalliumContext::GalliumContext(ulong options)
154 :
155 fOptions(options),
156 fCurrentContext(0),
157 fScreen(NULL)
158 {
159 CALLED();
160
161 // Make all contexts a known value
162 for (context_id i = 0; i < CONTEXT_MAX; i++)
163 fContext[i] = NULL;
164
165 CreateScreen();
166
167 pipe_mutex_init(fMutex);
168 }
169
170
171 GalliumContext::~GalliumContext()
172 {
173 CALLED();
174
175 // Destroy our contexts
176 pipe_mutex_lock(fMutex);
177 for (context_id i = 0; i < CONTEXT_MAX; i++)
178 DestroyContext(i);
179 pipe_mutex_unlock(fMutex);
180
181 pipe_mutex_destroy(fMutex);
182
183 // TODO: Destroy fScreen
184 }
185
186
187 status_t
188 GalliumContext::CreateScreen()
189 {
190 CALLED();
191
192 // Allocate winsys and attach callback hooks
193 struct sw_winsys* winsys = hgl_create_sw_winsys();
194
195 if (!winsys) {
196 ERROR("%s: Couldn't allocate sw_winsys!\n", __func__);
197 return B_ERROR;
198 }
199
200 fScreen = sw_screen_create(winsys);
201
202 if (fScreen == NULL) {
203 ERROR("%s: Couldn't create screen!\n", __FUNCTION__);
204 FREE(winsys);
205 return B_ERROR;
206 }
207
208 debug_screen_wrap(fScreen);
209
210 const char* driverName = fScreen->get_name(fScreen);
211 ERROR("%s: Using %s driver.\n", __func__, driverName);
212
213 return B_OK;
214 }
215
216
217 context_id
218 GalliumContext::CreateContext(Bitmap *bitmap)
219 {
220 CALLED();
221
222 struct hgl_context* context = CALLOC_STRUCT(hgl_context);
223
224 if (!context) {
225 ERROR("%s: Couldn't create pipe context!\n", __FUNCTION__);
226 return 0;
227 }
228
229 // Set up the initial things our context needs
230 context->bitmap = bitmap;
231 context->colorSpace = get_bitmap_color_space(bitmap);
232 context->draw = NULL;
233 context->read = NULL;
234 context->st = NULL;
235
236 context->api = st_gl_api_create();
237 if (!context->api) {
238 ERROR("%s: Couldn't obtain Mesa state tracker API!\n", __func__);
239 return -1;
240 }
241
242 context->manager = CALLOC_STRUCT(st_manager);
243 if (!context->manager) {
244 ERROR("%s: Couldn't allocate Mesa state tracker manager!\n", __func__);
245 return -1;
246 }
247 context->manager->get_param = hook_stm_get_param;
248
249 // Calculate visual configuration
250 const GLboolean rgbFlag = ((fOptions & BGL_INDEX) == 0);
251 const GLboolean alphaFlag = ((fOptions & BGL_ALPHA) == BGL_ALPHA);
252 const GLboolean dblFlag = ((fOptions & BGL_DOUBLE) == BGL_DOUBLE);
253 const GLboolean stereoFlag = false;
254 const GLint depth = (fOptions & BGL_DEPTH) ? 24 : 0;
255 const GLint stencil = (fOptions & BGL_STENCIL) ? 8 : 0;
256 const GLint accum = 0; // (options & BGL_ACCUM) ? 16 : 0;
257 const GLint red = rgbFlag ? 8 : 0;
258 const GLint green = rgbFlag ? 8 : 0;
259 const GLint blue = rgbFlag ? 8 : 0;
260 const GLint alpha = alphaFlag ? 8 : 0;
261
262 TRACE("rgb :\t%d\n", (bool)rgbFlag);
263 TRACE("alpha :\t%d\n", (bool)alphaFlag);
264 TRACE("dbl :\t%d\n", (bool)dblFlag);
265 TRACE("stereo :\t%d\n", (bool)stereoFlag);
266 TRACE("depth :\t%d\n", depth);
267 TRACE("stencil :\t%d\n", stencil);
268 TRACE("accum :\t%d\n", accum);
269 TRACE("red :\t%d\n", red);
270 TRACE("green :\t%d\n", green);
271 TRACE("blue :\t%d\n", blue);
272 TRACE("alpha :\t%d\n", alpha);
273
274 gl_config* glVisual = _mesa_create_visual(dblFlag, stereoFlag, red, green,
275 blue, alpha, depth, stencil, accum, accum, accum, alpha ? accum : 0, 1);
276
277 if (!glVisual) {
278 ERROR("%s: Couldn't create Mesa visual!\n", __func__);
279 return -1;
280 }
281
282 TRACE("depthBits :\t%d\n", glVisual->depthBits);
283 TRACE("stencilBits :\t%d\n", glVisual->stencilBits);
284
285 // Convert Mesa calculated visual into state tracker visual
286 context->stVisual = hgl_fill_st_visual(glVisual);
287
288 context->draw = new GalliumFramebuffer(context->stVisual, (void*)this);
289 context->read = new GalliumFramebuffer(context->stVisual, (void*)this);
290
291 if (!context->draw || !context->read) {
292 ERROR("%s: Problem allocating framebuffer!\n", __func__);
293 _mesa_destroy_visual(glVisual);
294 return -1;
295 }
296
297 // We need to assign the screen *before* calling st_api create_context
298 context->manager->screen = fScreen;
299
300 // Build state tracker attributes
301 struct st_context_attribs attribs;
302 memset(&attribs, 0, sizeof(attribs));
303 attribs.options.force_glsl_extensions_warn = false;
304 attribs.profile = ST_PROFILE_DEFAULT;
305 attribs.visual = *context->stVisual;
306 attribs.major = 1;
307 attribs.minor = 0;
308 //attribs.flags |= ST_CONTEXT_FLAG_DEBUG;
309
310 struct st_api* api = context->api;
311
312 // Create context using state tracker api call
313 enum st_context_error result;
314 context->st = api->create_context(api, context->manager, &attribs,
315 &result, context->st);
316
317 if (!context->st) {
318 ERROR("%s: Couldn't create mesa state tracker context!\n",
319 __func__);
320 switch (result) {
321 case ST_CONTEXT_SUCCESS:
322 ERROR("%s: State tracker error: SUCCESS?\n", __func__);
323 break;
324 case ST_CONTEXT_ERROR_NO_MEMORY:
325 ERROR("%s: State tracker error: NO_MEMORY\n", __func__);
326 break;
327 case ST_CONTEXT_ERROR_BAD_API:
328 ERROR("%s: State tracker error: BAD_API\n", __func__);
329 break;
330 case ST_CONTEXT_ERROR_BAD_VERSION:
331 ERROR("%s: State tracker error: BAD_VERSION\n", __func__);
332 break;
333 case ST_CONTEXT_ERROR_BAD_FLAG:
334 ERROR("%s: State tracker error: BAD_FLAG\n", __func__);
335 break;
336 case ST_CONTEXT_ERROR_UNKNOWN_ATTRIBUTE:
337 ERROR("%s: State tracker error: BAD_ATTRIBUTE\n", __func__);
338 break;
339 case ST_CONTEXT_ERROR_UNKNOWN_FLAG:
340 ERROR("%s: State tracker error: UNKNOWN_FLAG\n", __func__);
341 break;
342 }
343
344 FREE(context);
345 return -1;
346 }
347
348 // Init Gallium3D Post Processing
349 //context->postProcess = pp_init(fScreen, context->postProcessEnable);
350
351 assert(!context->st->st_manager_private);
352 context->st->st_manager_private = (void*)this;
353
354 struct st_context *stContext = (struct st_context*)context->st;
355
356 stContext->ctx->Driver.Viewport = hgl_viewport;
357
358 // TODO: Closely review this next context logic...
359 context_id contextNext = -1;
360
361 pipe_mutex_lock(fMutex);
362 for (context_id i = 0; i < CONTEXT_MAX; i++) {
363 if (fContext[i] == NULL) {
364 fContext[i] = context;
365 contextNext = i;
366 break;
367 }
368 }
369 pipe_mutex_unlock(fMutex);
370
371 if (contextNext < 0) {
372 ERROR("%s: The next context is invalid... something went wrong!\n",
373 __func__);
374 //st_destroy_context(context->st);
375 FREE(context);
376 _mesa_destroy_visual(glVisual);
377 return -1;
378 }
379
380 TRACE("%s: context #%" B_PRIu64 " is the next available context\n",
381 __func__, contextNext);
382
383 return contextNext;
384 }
385
386
387 void
388 GalliumContext::DestroyContext(context_id contextID)
389 {
390 // fMutex should be locked *before* calling DestoryContext
391
392 // See if context is used
393 if (!fContext[contextID])
394 return;
395
396 if (fContext[contextID]->st) {
397 fContext[contextID]->st->flush(fContext[contextID]->st, 0, NULL);
398 fContext[contextID]->st->destroy(fContext[contextID]->st);
399 }
400
401 if (fContext[contextID]->postProcess)
402 pp_free(fContext[contextID]->postProcess);
403
404 // Delete framebuffer objects
405 if (fContext[contextID]->read)
406 delete fContext[contextID]->read;
407 if (fContext[contextID]->draw)
408 delete fContext[contextID]->draw;
409
410 if (fContext[contextID]->stVisual)
411 FREE(fContext[contextID]->stVisual);
412
413 if (fContext[contextID]->manager)
414 FREE(fContext[contextID]->manager);
415
416 FREE(fContext[contextID]);
417 }
418
419
420 status_t
421 GalliumContext::SetCurrentContext(Bitmap *bitmap, context_id contextID)
422 {
423 CALLED();
424
425 if (contextID < 0 || contextID > CONTEXT_MAX) {
426 ERROR("%s: Invalid context ID range!\n", __func__);
427 return B_ERROR;
428 }
429
430 pipe_mutex_lock(fMutex);
431 context_id oldContextID = fCurrentContext;
432 struct hgl_context* context = fContext[contextID];
433 pipe_mutex_unlock(fMutex);
434
435 if (!context) {
436 ERROR("%s: Invalid context provided (#%" B_PRIu64 ")!\n",
437 __func__, contextID);
438 return B_ERROR;
439 }
440
441 struct st_api* api = context->api;
442
443 if (!bitmap) {
444 api->make_current(context->api, NULL, NULL, NULL);
445 return B_OK;
446 }
447
448 // Everything seems valid, lets set the new context.
449 fCurrentContext = contextID;
450
451 if (oldContextID > 0 && oldContextID != contextID) {
452 fContext[oldContextID]->st->flush(fContext[oldContextID]->st,
453 ST_FLUSH_FRONT, NULL);
454 }
455
456 // We need to lock and unlock framebuffers before accessing them
457 context->draw->Lock();
458 context->read->Lock();
459 api->make_current(context->api, context->st, context->draw->fBuffer,
460 context->read->fBuffer);
461 context->draw->Unlock();
462 context->read->Unlock();
463
464 // TODO: Init textures before post-processing them
465 #if 0
466 pp_init_fbos(context->postProcess,
467 context->textures[ST_ATTACHMENT_BACK_LEFT]->width0,
468 context->textures[ST_ATTACHMENT_BACK_LEFT]->height0);
469 #endif
470
471 context->bitmap = bitmap;
472 //context->st->pipe->priv = context;
473
474 return B_OK;
475 }
476
477
478 status_t
479 GalliumContext::SwapBuffers(context_id contextID)
480 {
481 CALLED();
482
483 pipe_mutex_lock(fMutex);
484 struct hgl_context *context = fContext[contextID];
485 pipe_mutex_unlock(fMutex);
486
487 if (!context) {
488 ERROR("%s: context not found\n", __func__);
489 return B_ERROR;
490 }
491
492 // TODO: Where did st_notify_swapbuffers go?
493 //st_notify_swapbuffers(context->draw->stfb);
494
495 context->st->flush(context->st, ST_FLUSH_FRONT, NULL);
496
497 struct st_context *stContext = (struct st_context*)context->st;
498
499 unsigned nColorBuffers = stContext->state.framebuffer.nr_cbufs;
500 for (unsigned i = 0; i < nColorBuffers; i++) {
501 pipe_surface* surface = stContext->state.framebuffer.cbufs[i];
502 if (!surface) {
503 ERROR("%s: Color buffer %d invalid!\n", __func__, i);
504 continue;
505 }
506
507 TRACE("%s: Flushing color buffer #%d\n", __func__, i);
508
509 // We pass our destination bitmap to flush_fronbuffer which passes it
510 // to the private winsys display call.
511 fScreen->flush_frontbuffer(fScreen, surface->texture, 0, 0,
512 context->bitmap);
513 }
514
515 #if 0
516 // TODO... should we flush the z stencil buffer?
517 pipe_surface* zSurface = stContext->state.framebuffer.zsbuf;
518 fScreen->flush_frontbuffer(fScreen, surface->texture, 0, 0,
519 context->bitmap);
520 #endif
521
522 return B_OK;
523 }