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