2 * Copyright 2012, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
6 * Artur Wyszynski, harakash@gmail.com
7 * Alexander von Gluck IV, kallisti5@unixzen.com
11 #include "GalliumContext.h"
15 #include "bitmap_wrapper.h"
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"
30 #include "target-helpers/inline_sw_helper.h"
31 #include "target-helpers/inline_debug_helper.h"
36 # define TRACE(x...) printf("GalliumContext: " x)
37 # define CALLED() TRACE("CALLED: %s\n", __PRETTY_FUNCTION__)
42 #define ERROR(x...) printf("GalliumContext: " x)
46 hgl_viewport(struct gl_context
* glContext
, GLint x
, GLint y
,
47 GLsizei width
, GLsizei height
)
49 TRACE("%s(glContext: %p, x: %d, y: %d, w: %d, h: %d\n", __func__
,
50 glContext
, x
, y
, width
, height
);
52 struct gl_framebuffer
*draw
= glContext
->WinSysDrawBuffer
;
53 struct gl_framebuffer
*read
= glContext
->WinSysReadBuffer
;
55 // TODO: SLOW! We need to check for changes in bitmap vs gl_framebuffer
56 // size before doing a _mesa_resize_framebuffer.
58 _mesa_resize_framebuffer(glContext
, draw
, width
, height
);
60 _mesa_resize_framebuffer(glContext
, read
, width
, height
);
65 hgl_fill_st_visual(gl_config
* glVisual
)
67 struct st_visual
* stVisual
= CALLOC_STRUCT(st_visual
);
69 ERROR("%s: Couldn't allocate st_visual\n", __func__
);
73 // Determine color format
74 if (glVisual
->redBits
== 8) {
75 if (glVisual
->alphaBits
== 8)
76 stVisual
->color_format
= PIPE_FORMAT_B8G8R8A8_UNORM
;
78 stVisual
->color_format
= PIPE_FORMAT_B8G8R8X8_UNORM
;
80 stVisual
->color_format
= PIPE_FORMAT_B5G6R5_UNORM
;
83 // Determine depth stencil format
84 switch (glVisual
->depthBits
) {
87 stVisual
->depth_stencil_format
= PIPE_FORMAT_NONE
;
90 stVisual
->depth_stencil_format
= PIPE_FORMAT_Z16_UNORM
;
93 if (glVisual
->stencilBits
== 0) {
94 stVisual
->depth_stencil_format
= PIPE_FORMAT_Z24X8_UNORM
;
95 // or PIPE_FORMAT_X8Z24_UNORM?
97 stVisual
->depth_stencil_format
= PIPE_FORMAT_Z24_UNORM_S8_UINT
;
98 // or PIPE_FORMAT_S8_UINT_Z24_UNORM?
102 stVisual
->depth_stencil_format
= PIPE_FORMAT_Z32_UNORM
;
106 stVisual
->accum_format
= (glVisual
->haveAccumBuffer
)
107 ? PIPE_FORMAT_R16G16B16A16_SNORM
: PIPE_FORMAT_NONE
;
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
;
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
;
122 if (glVisual
->haveDepthBuffer
|| glVisual
->haveStencilBuffer
)
123 stVisual
->buffer_mask
|= ST_ATTACHMENT_DEPTH_STENCIL_MASK
;
129 static INLINE
unsigned
130 round_up(unsigned n
, unsigned multiple
)
132 return (n
+ multiple
- 1) & ~(multiple
- 1);
137 hook_stm_get_param(struct st_manager
*smapi
, enum st_manager_param param
)
142 case ST_MANAGER_BROKEN_INVALIDATE
:
143 TRACE("%s: TODO: How should we handle BROKEN_INVALIDATE calls?\n",
145 // For now we force validation of the framebuffer.
153 GalliumContext::GalliumContext(ulong options
)
161 // Make all contexts a known value
162 for (context_id i
= 0; i
< CONTEXT_MAX
; i
++)
167 pipe_mutex_init(fMutex
);
171 GalliumContext::~GalliumContext()
175 // Destroy our contexts
176 pipe_mutex_lock(fMutex
);
177 for (context_id i
= 0; i
< CONTEXT_MAX
; i
++)
179 pipe_mutex_unlock(fMutex
);
181 pipe_mutex_destroy(fMutex
);
183 // TODO: Destroy fScreen
188 GalliumContext::CreateScreen()
192 // Allocate winsys and attach callback hooks
193 struct sw_winsys
* winsys
= hgl_create_sw_winsys();
196 ERROR("%s: Couldn't allocate sw_winsys!\n", __func__
);
200 fScreen
= sw_screen_create(winsys
);
202 if (fScreen
== NULL
) {
203 ERROR("%s: Couldn't create screen!\n", __FUNCTION__
);
208 debug_screen_wrap(fScreen
);
210 const char* driverName
= fScreen
->get_name(fScreen
);
211 ERROR("%s: Using %s driver.\n", __func__
, driverName
);
218 GalliumContext::CreateContext(Bitmap
*bitmap
)
222 struct hgl_context
* context
= CALLOC_STRUCT(hgl_context
);
225 ERROR("%s: Couldn't create pipe context!\n", __FUNCTION__
);
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
;
236 context
->api
= st_gl_api_create();
238 ERROR("%s: Couldn't obtain Mesa state tracker API!\n", __func__
);
242 context
->manager
= CALLOC_STRUCT(st_manager
);
243 if (!context
->manager
) {
244 ERROR("%s: Couldn't allocate Mesa state tracker manager!\n", __func__
);
247 context
->manager
->get_param
= hook_stm_get_param
;
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;
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
);
274 gl_config
* glVisual
= _mesa_create_visual(dblFlag
, stereoFlag
, red
, green
,
275 blue
, alpha
, depth
, stencil
, accum
, accum
, accum
, alpha
? accum
: 0, 1);
278 ERROR("%s: Couldn't create Mesa visual!\n", __func__
);
282 TRACE("depthBits :\t%d\n", glVisual
->depthBits
);
283 TRACE("stencilBits :\t%d\n", glVisual
->stencilBits
);
285 // Convert Mesa calculated visual into state tracker visual
286 context
->stVisual
= hgl_fill_st_visual(glVisual
);
288 context
->draw
= new GalliumFramebuffer(context
->stVisual
, (void*)this);
289 context
->read
= new GalliumFramebuffer(context
->stVisual
, (void*)this);
291 if (!context
->draw
|| !context
->read
) {
292 ERROR("%s: Problem allocating framebuffer!\n", __func__
);
293 _mesa_destroy_visual(glVisual
);
297 // We need to assign the screen *before* calling st_api create_context
298 context
->manager
->screen
= fScreen
;
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
;
308 //attribs.flags |= ST_CONTEXT_FLAG_DEBUG;
310 struct st_api
* api
= context
->api
;
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
);
318 ERROR("%s: Couldn't create mesa state tracker context!\n",
321 case ST_CONTEXT_SUCCESS
:
322 ERROR("%s: State tracker error: SUCCESS?\n", __func__
);
324 case ST_CONTEXT_ERROR_NO_MEMORY
:
325 ERROR("%s: State tracker error: NO_MEMORY\n", __func__
);
327 case ST_CONTEXT_ERROR_BAD_API
:
328 ERROR("%s: State tracker error: BAD_API\n", __func__
);
330 case ST_CONTEXT_ERROR_BAD_VERSION
:
331 ERROR("%s: State tracker error: BAD_VERSION\n", __func__
);
333 case ST_CONTEXT_ERROR_BAD_FLAG
:
334 ERROR("%s: State tracker error: BAD_FLAG\n", __func__
);
336 case ST_CONTEXT_ERROR_UNKNOWN_ATTRIBUTE
:
337 ERROR("%s: State tracker error: BAD_ATTRIBUTE\n", __func__
);
339 case ST_CONTEXT_ERROR_UNKNOWN_FLAG
:
340 ERROR("%s: State tracker error: UNKNOWN_FLAG\n", __func__
);
348 // Init Gallium3D Post Processing
349 //context->postProcess = pp_init(fScreen, context->postProcessEnable);
351 assert(!context
->st
->st_manager_private
);
352 context
->st
->st_manager_private
= (void*)this;
354 struct st_context
*stContext
= (struct st_context
*)context
->st
;
356 stContext
->ctx
->Driver
.Viewport
= hgl_viewport
;
358 // TODO: Closely review this next context logic...
359 context_id contextNext
= -1;
361 pipe_mutex_lock(fMutex
);
362 for (context_id i
= 0; i
< CONTEXT_MAX
; i
++) {
363 if (fContext
[i
] == NULL
) {
364 fContext
[i
] = context
;
369 pipe_mutex_unlock(fMutex
);
371 if (contextNext
< 0) {
372 ERROR("%s: The next context is invalid... something went wrong!\n",
374 //st_destroy_context(context->st);
376 _mesa_destroy_visual(glVisual
);
380 TRACE("%s: context #%" B_PRIu64
" is the next available context\n",
381 __func__
, contextNext
);
388 GalliumContext::DestroyContext(context_id contextID
)
390 // fMutex should be locked *before* calling DestoryContext
392 // See if context is used
393 if (!fContext
[contextID
])
396 if (fContext
[contextID
]->st
) {
397 fContext
[contextID
]->st
->flush(fContext
[contextID
]->st
, 0, NULL
);
398 fContext
[contextID
]->st
->destroy(fContext
[contextID
]->st
);
401 if (fContext
[contextID
]->postProcess
)
402 pp_free(fContext
[contextID
]->postProcess
);
404 // Delete framebuffer objects
405 if (fContext
[contextID
]->read
)
406 delete fContext
[contextID
]->read
;
407 if (fContext
[contextID
]->draw
)
408 delete fContext
[contextID
]->draw
;
410 if (fContext
[contextID
]->stVisual
)
411 FREE(fContext
[contextID
]->stVisual
);
413 if (fContext
[contextID
]->manager
)
414 FREE(fContext
[contextID
]->manager
);
416 FREE(fContext
[contextID
]);
421 GalliumContext::SetCurrentContext(Bitmap
*bitmap
, context_id contextID
)
425 if (contextID
< 0 || contextID
> CONTEXT_MAX
) {
426 ERROR("%s: Invalid context ID range!\n", __func__
);
430 pipe_mutex_lock(fMutex
);
431 context_id oldContextID
= fCurrentContext
;
432 struct hgl_context
* context
= fContext
[contextID
];
433 pipe_mutex_unlock(fMutex
);
436 ERROR("%s: Invalid context provided (#%" B_PRIu64
")!\n",
437 __func__
, contextID
);
441 struct st_api
* api
= context
->api
;
444 api
->make_current(context
->api
, NULL
, NULL
, NULL
);
448 // Everything seems valid, lets set the new context.
449 fCurrentContext
= contextID
;
451 if (oldContextID
> 0 && oldContextID
!= contextID
) {
452 fContext
[oldContextID
]->st
->flush(fContext
[oldContextID
]->st
,
453 ST_FLUSH_FRONT
, NULL
);
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();
464 // TODO: Init textures before post-processing them
466 pp_init_fbos(context
->postProcess
,
467 context
->textures
[ST_ATTACHMENT_BACK_LEFT
]->width0
,
468 context
->textures
[ST_ATTACHMENT_BACK_LEFT
]->height0
);
471 context
->bitmap
= bitmap
;
472 //context->st->pipe->priv = context;
479 GalliumContext::SwapBuffers(context_id contextID
)
483 pipe_mutex_lock(fMutex
);
484 struct hgl_context
*context
= fContext
[contextID
];
485 pipe_mutex_unlock(fMutex
);
488 ERROR("%s: context not found\n", __func__
);
492 // TODO: Where did st_notify_swapbuffers go?
493 //st_notify_swapbuffers(context->draw->stfb);
495 context
->st
->flush(context
->st
, ST_FLUSH_FRONT
, NULL
);
497 struct st_context
*stContext
= (struct st_context
*)context
->st
;
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
];
503 ERROR("%s: Color buffer %d invalid!\n", __func__
, i
);
507 TRACE("%s: Flushing color buffer #%d\n", __func__
, i
);
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,
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,