blob: 0e122fe86ae90a31aed79a945c564a0311febe93 [file] [log] [blame]
/*
* Copyright 2012-2014, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Artur Wyszynski, harakash@gmail.com
* Alexander von Gluck IV, kallisti5@unixzen.com
*/
#include "hgl_context.h"
#include <stdio.h>
#include "pipe/p_format.h"
#include "util/u_atomic.h"
#include "util/u_format.h"
#include "util/u_memory.h"
#include "util/u_inlines.h"
#include "state_tracker/st_gl_api.h" /* for st_gl_api_create */
#include "GLView.h"
#ifdef DEBUG
# define TRACE(x...) printf("hgl:state_tracker: " x)
# define CALLED() TRACE("CALLED: %s\n", __PRETTY_FUNCTION__)
#else
# define TRACE(x...)
# define CALLED()
#endif
#define ERROR(x...) printf("hgl:state_tracker: " x)
// Perform a safe void to hgl_context cast
static inline struct hgl_context*
hgl_st_context(struct st_context_iface *stctxi)
{
struct hgl_context* context;
assert(stctxi);
context = (struct hgl_context*)stctxi->st_manager_private;
assert(context);
return context;
}
// Perform a safe void to hgl_buffer cast
static inline struct hgl_buffer*
hgl_st_framebuffer(struct st_framebuffer_iface *stfbi)
{
struct hgl_buffer* buffer;
assert(stfbi);
buffer = (struct hgl_buffer*)stfbi->st_manager_private;
assert(buffer);
return buffer;
}
static boolean
hgl_st_framebuffer_flush_front(struct st_context_iface *stctxi,
struct st_framebuffer_iface* stfbi, enum st_attachment_type statt)
{
CALLED();
//struct hgl_context* context = hgl_st_context(stctxi);
//struct hgl_buffer* buffer = hgl_st_context(stfbi);
#if 0
struct stw_st_framebuffer *stwfb = stw_st_framebuffer(stfb);
pipe_mutex_lock(stwfb->fb->mutex);
struct pipe_resource* resource = textures[statt];
if (resource)
stw_framebuffer_present_locked(...);
#endif
return TRUE;
}
static boolean
hgl_st_framebuffer_validate_textures(struct st_framebuffer_iface *stfbi,
unsigned width, unsigned height, unsigned mask)
{
struct hgl_buffer* buffer;
enum st_attachment_type i;
struct pipe_resource templat;
CALLED();
buffer = hgl_st_framebuffer(stfbi);
if (buffer->width != width || buffer->height != height) {
for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
pipe_resource_reference(&buffer->textures[i], NULL);
}
memset(&templat, 0, sizeof(templat));
templat.target = buffer->target;
templat.width0 = width;
templat.height0 = height;
templat.depth0 = 1;
templat.array_size = 1;
templat.last_level = 0;
for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
enum pipe_format format;
unsigned bind;
switch (i) {
case ST_ATTACHMENT_FRONT_LEFT:
case ST_ATTACHMENT_BACK_LEFT:
case ST_ATTACHMENT_FRONT_RIGHT:
case ST_ATTACHMENT_BACK_RIGHT:
format = buffer->visual->color_format;
bind = PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_RENDER_TARGET;
break;
case ST_ATTACHMENT_DEPTH_STENCIL:
format = buffer->visual->depth_stencil_format;
bind = PIPE_BIND_DEPTH_STENCIL;
break;
default:
format = PIPE_FORMAT_NONE;
bind = 0;
break;
}
if (format != PIPE_FORMAT_NONE) {
templat.format = format;
templat.bind = bind;
buffer->textures[i] = buffer->screen->resource_create(buffer->screen,
&templat);
if (!buffer->textures[i])
return FALSE;
}
}
buffer->width = width;
buffer->height = height;
buffer->mask = mask;
return TRUE;
}
/**
* Called by the st manager to validate the framebuffer (allocate
* its resources).
*/
static boolean
hgl_st_framebuffer_validate(struct st_context_iface *stctxi,
struct st_framebuffer_iface *stfbi, const enum st_attachment_type *statts,
unsigned count, struct pipe_resource **out)
{
struct hgl_context* context;
struct hgl_buffer* buffer;
unsigned stAttachmentMask, newMask;
unsigned i;
boolean resized;
CALLED();
context = hgl_st_context(stctxi);
buffer = hgl_st_framebuffer(stfbi);
//int32 width = 0;
//int32 height = 0;
//get_bitmap_size(context->bitmap, &width, &height);
// Build mask of current attachments
stAttachmentMask = 0;
for (i = 0; i < count; i++)
stAttachmentMask |= 1 << statts[i];
newMask = stAttachmentMask & ~buffer->mask;
resized = (buffer->width != context->width)
|| (buffer->height != context->height);
if (resized || newMask) {
boolean ret;
TRACE("%s: resize event. old: %d x %d; new: %d x %d\n", __func__,
buffer->width, buffer->height, context->width, context->height);
ret = hgl_st_framebuffer_validate_textures(stfbi,
context->width, context->height, stAttachmentMask);
if (!ret)
return ret;
// TODO: Simply update attachments
//if (!resized) {
//}
}
for (i = 0; i < count; i++) {
out[i] = NULL;
pipe_resource_reference(&out[i], buffer->textures[statts[i]]);
}
return TRUE;
}
static int
hgl_st_manager_get_param(struct st_manager *smapi, enum st_manager_param param)
{
CALLED();
switch (param) {
case ST_MANAGER_BROKEN_INVALIDATE:
return 1;
}
return 0;
}
/**
* Create new framebuffer
*/
struct hgl_buffer *
hgl_create_st_framebuffer(struct hgl_context* context)
{
struct hgl_buffer *buffer;
CALLED();
// Our requires before creating a framebuffer
assert(context);
assert(context->screen);
assert(context->stVisual);
buffer = CALLOC_STRUCT(hgl_buffer);
assert(buffer);
// calloc and configure our st_framebuffer interface
buffer->stfbi = CALLOC_STRUCT(st_framebuffer_iface);
assert(buffer->stfbi);
// Prepare our buffer
buffer->visual = context->stVisual;
buffer->screen = context->screen;
if (context->screen->get_param(buffer->screen, PIPE_CAP_NPOT_TEXTURES))
buffer->target = PIPE_TEXTURE_2D;
else
buffer->target = PIPE_TEXTURE_RECT;
// Prepare our state_tracker interface
buffer->stfbi->flush_front = hgl_st_framebuffer_flush_front;
buffer->stfbi->validate = hgl_st_framebuffer_validate;
buffer->stfbi->visual = context->stVisual;
p_atomic_set(&buffer->stfbi->stamp, 1);
buffer->stfbi->st_manager_private = (void*)buffer;
return buffer;
}
struct st_api*
hgl_create_st_api()
{
CALLED();
return st_gl_api_create();
}
struct st_manager *
hgl_create_st_manager(struct hgl_context* context)
{
struct st_manager* manager;
CALLED();
// Required things
assert(context);
assert(context->screen);
manager = CALLOC_STRUCT(st_manager);
assert(manager);
//manager->display = dpy;
manager->screen = context->screen;
manager->get_param = hgl_st_manager_get_param;
return manager;
}
void
hgl_destroy_st_manager(struct st_manager *manager)
{
CALLED();
FREE(manager);
}
struct st_visual*
hgl_create_st_visual(ulong options)
{
struct st_visual* visual;
CALLED();
visual = CALLOC_STRUCT(st_visual);
assert(visual);
// Determine color format
if ((options & BGL_INDEX) != 0) {
// Index color
visual->color_format = PIPE_FORMAT_B5G6R5_UNORM;
// TODO: Indexed color depth buffer?
visual->depth_stencil_format = PIPE_FORMAT_NONE;
} else {
// RGB color
visual->color_format = (options & BGL_ALPHA)
? PIPE_FORMAT_BGRA8888_UNORM : PIPE_FORMAT_BGRX8888_UNORM;
// TODO: Determine additional stencil formats
visual->depth_stencil_format = (options & BGL_DEPTH)
? PIPE_FORMAT_Z24_UNORM_S8_UINT : PIPE_FORMAT_NONE;
}
visual->accum_format = (options & BGL_ACCUM)
? PIPE_FORMAT_R16G16B16A16_SNORM : PIPE_FORMAT_NONE;
visual->buffer_mask |= ST_ATTACHMENT_FRONT_LEFT_MASK;
visual->render_buffer = ST_ATTACHMENT_FRONT_LEFT;
if ((options & BGL_DOUBLE) != 0) {
visual->buffer_mask |= ST_ATTACHMENT_BACK_LEFT_MASK;
visual->render_buffer = ST_ATTACHMENT_BACK_LEFT;
}
#if 0
if ((options & BGL_STEREO) != 0) {
visual->buffer_mask |= ST_ATTACHMENT_FRONT_RIGHT_MASK;
if ((options & BGL_DOUBLE) != 0)
visual->buffer_mask |= ST_ATTACHMENT_BACK_RIGHT_MASK;
}
#endif
if ((options & BGL_DEPTH) || (options & BGL_STENCIL))
visual->buffer_mask |= ST_ATTACHMENT_DEPTH_STENCIL_MASK;
TRACE("%s: Visual color format: %s\n", __func__,
util_format_name(visual->color_format));
return visual;
}
void
hgl_destroy_st_visual(struct st_visual* visual)
{
CALLED();
FREE(visual);
}