17ec681f3Smrg/*
27ec681f3Smrg * Copyright 2012-2014, Haiku, Inc. All Rights Reserved.
37ec681f3Smrg * Distributed under the terms of the MIT License.
47ec681f3Smrg *
57ec681f3Smrg * Authors:
67ec681f3Smrg *      Artur Wyszynski, harakash@gmail.com
77ec681f3Smrg *      Alexander von Gluck IV, kallisti5@unixzen.com
87ec681f3Smrg */
97ec681f3Smrg
107ec681f3Smrg#include "hgl_context.h"
117ec681f3Smrg
127ec681f3Smrg#include <stdio.h>
137ec681f3Smrg
147ec681f3Smrg#include "pipe/p_format.h"
157ec681f3Smrg#include "util/u_atomic.h"
167ec681f3Smrg#include "util/format/u_format.h"
177ec681f3Smrg#include "util/u_memory.h"
187ec681f3Smrg#include "util/u_inlines.h"
197ec681f3Smrg#include "state_tracker/st_gl_api.h" /* for st_gl_api_create */
207ec681f3Smrg
217ec681f3Smrg#include "GLView.h"
227ec681f3Smrg
237ec681f3Smrg
247ec681f3Smrg#ifdef DEBUG
257ec681f3Smrg#   define TRACE(x...) printf("hgl:frontend: " x)
267ec681f3Smrg#   define CALLED() TRACE("CALLED: %s\n", __PRETTY_FUNCTION__)
277ec681f3Smrg#else
287ec681f3Smrg#   define TRACE(x...)
297ec681f3Smrg#   define CALLED()
307ec681f3Smrg#endif
317ec681f3Smrg#define ERROR(x...) printf("hgl:frontend: " x)
327ec681f3Smrg
337ec681f3Smrg
347ec681f3Smrg// Perform a safe void to hgl_context cast
357ec681f3Smrgstatic inline struct hgl_context*
367ec681f3Smrghgl_st_context(struct st_context_iface *stctxi)
377ec681f3Smrg{
387ec681f3Smrg	struct hgl_context* context;
397ec681f3Smrg	assert(stctxi);
407ec681f3Smrg	context = (struct hgl_context*)stctxi->st_manager_private;
417ec681f3Smrg	assert(context);
427ec681f3Smrg	return context;
437ec681f3Smrg}
447ec681f3Smrg
457ec681f3Smrg
467ec681f3Smrg// Perform a safe void to hgl_buffer cast
477ec681f3Smrg//static inline struct hgl_buffer*
487ec681f3Smrgstruct hgl_buffer*
497ec681f3Smrghgl_st_framebuffer(struct st_framebuffer_iface *stfbi)
507ec681f3Smrg{
517ec681f3Smrg	struct hgl_buffer* buffer;
527ec681f3Smrg	assert(stfbi);
537ec681f3Smrg	buffer = (struct hgl_buffer*)stfbi->st_manager_private;
547ec681f3Smrg	assert(buffer);
557ec681f3Smrg	return buffer;
567ec681f3Smrg}
577ec681f3Smrg
587ec681f3Smrg
597ec681f3Smrgstatic bool
607ec681f3Smrghgl_st_framebuffer_flush_front(struct st_context_iface* stctxi,
617ec681f3Smrg	struct st_framebuffer_iface* stfbi, enum st_attachment_type statt)
627ec681f3Smrg{
637ec681f3Smrg	CALLED();
647ec681f3Smrg
657ec681f3Smrg	struct hgl_buffer* buffer = hgl_st_framebuffer(stfbi);
667ec681f3Smrg	struct pipe_resource* ptex = buffer->textures[statt];
677ec681f3Smrg
687ec681f3Smrg	if (statt != ST_ATTACHMENT_FRONT_LEFT)
697ec681f3Smrg		return false;
707ec681f3Smrg
717ec681f3Smrg	if (!ptex)
727ec681f3Smrg		return true;
737ec681f3Smrg
747ec681f3Smrg	// TODO: pipe_context here??? Might be needed for hw renderers
757ec681f3Smrg	buffer->screen->flush_frontbuffer(buffer->screen, NULL, ptex, 0, 0,
767ec681f3Smrg		buffer->winsysContext, NULL);
777ec681f3Smrg
787ec681f3Smrg	return true;
797ec681f3Smrg}
807ec681f3Smrg
817ec681f3Smrg
827ec681f3Smrgstatic bool
837ec681f3Smrghgl_st_framebuffer_validate_textures(struct st_framebuffer_iface *stfbi,
847ec681f3Smrg	unsigned width, unsigned height, unsigned mask)
857ec681f3Smrg{
867ec681f3Smrg	struct hgl_buffer* buffer;
877ec681f3Smrg	enum st_attachment_type i;
887ec681f3Smrg	struct pipe_resource templat;
897ec681f3Smrg
907ec681f3Smrg	CALLED();
917ec681f3Smrg
927ec681f3Smrg	buffer = hgl_st_framebuffer(stfbi);
937ec681f3Smrg
947ec681f3Smrg	if (buffer->width != width || buffer->height != height) {
957ec681f3Smrg		TRACE("validate_textures: size changed: %d, %d -> %d, %d\n",
967ec681f3Smrg			buffer->width, buffer->height, width, height);
977ec681f3Smrg		for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
987ec681f3Smrg			pipe_resource_reference(&buffer->textures[i], NULL);
997ec681f3Smrg	}
1007ec681f3Smrg
1017ec681f3Smrg	memset(&templat, 0, sizeof(templat));
1027ec681f3Smrg	templat.target = buffer->target;
1037ec681f3Smrg	templat.width0 = width;
1047ec681f3Smrg	templat.height0 = height;
1057ec681f3Smrg	templat.depth0 = 1;
1067ec681f3Smrg	templat.array_size = 1;
1077ec681f3Smrg	templat.last_level = 0;
1087ec681f3Smrg
1097ec681f3Smrg	for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
1107ec681f3Smrg		enum pipe_format format;
1117ec681f3Smrg		unsigned bind;
1127ec681f3Smrg
1137ec681f3Smrg		if (((1 << i) & buffer->visual->buffer_mask) && buffer->textures[i] == NULL) {
1147ec681f3Smrg			switch (i) {
1157ec681f3Smrg				case ST_ATTACHMENT_FRONT_LEFT:
1167ec681f3Smrg				case ST_ATTACHMENT_BACK_LEFT:
1177ec681f3Smrg				case ST_ATTACHMENT_FRONT_RIGHT:
1187ec681f3Smrg				case ST_ATTACHMENT_BACK_RIGHT:
1197ec681f3Smrg					format = buffer->visual->color_format;
1207ec681f3Smrg					bind = PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_RENDER_TARGET;
1217ec681f3Smrg					break;
1227ec681f3Smrg				case ST_ATTACHMENT_DEPTH_STENCIL:
1237ec681f3Smrg					format = buffer->visual->depth_stencil_format;
1247ec681f3Smrg					bind = PIPE_BIND_DEPTH_STENCIL;
1257ec681f3Smrg					break;
1267ec681f3Smrg				default:
1277ec681f3Smrg					format = PIPE_FORMAT_NONE;
1287ec681f3Smrg					bind = 0;
1297ec681f3Smrg					break;
1307ec681f3Smrg			}
1317ec681f3Smrg
1327ec681f3Smrg			if (format != PIPE_FORMAT_NONE) {
1337ec681f3Smrg				templat.format = format;
1347ec681f3Smrg				templat.bind = bind;
1357ec681f3Smrg				TRACE("resource_create(%d, %d, %d)\n", i, format, bind);
1367ec681f3Smrg				buffer->textures[i] = buffer->screen->resource_create(buffer->screen,
1377ec681f3Smrg					&templat);
1387ec681f3Smrg				if (!buffer->textures[i])
1397ec681f3Smrg					return FALSE;
1407ec681f3Smrg			}
1417ec681f3Smrg		}
1427ec681f3Smrg	}
1437ec681f3Smrg
1447ec681f3Smrg	buffer->width = width;
1457ec681f3Smrg	buffer->height = height;
1467ec681f3Smrg	buffer->mask = mask;
1477ec681f3Smrg
1487ec681f3Smrg	return true;
1497ec681f3Smrg}
1507ec681f3Smrg
1517ec681f3Smrg
1527ec681f3Smrg/**
1537ec681f3Smrg * Called by the st manager to validate the framebuffer (allocate
1547ec681f3Smrg * its resources).
1557ec681f3Smrg */
1567ec681f3Smrgstatic bool
1577ec681f3Smrghgl_st_framebuffer_validate(struct st_context_iface *stctxi,
1587ec681f3Smrg	struct st_framebuffer_iface *stfbi, const enum st_attachment_type *statts,
1597ec681f3Smrg	unsigned count, struct pipe_resource **out)
1607ec681f3Smrg{
1617ec681f3Smrg	struct hgl_context* context;
1627ec681f3Smrg	struct hgl_buffer* buffer;
1637ec681f3Smrg	unsigned stAttachmentMask, newMask;
1647ec681f3Smrg	unsigned i;
1657ec681f3Smrg	bool resized;
1667ec681f3Smrg
1677ec681f3Smrg	CALLED();
1687ec681f3Smrg
1697ec681f3Smrg	context = hgl_st_context(stctxi);
1707ec681f3Smrg	buffer = hgl_st_framebuffer(stfbi);
1717ec681f3Smrg
1727ec681f3Smrg	// Build mask of current attachments
1737ec681f3Smrg	stAttachmentMask = 0;
1747ec681f3Smrg	for (i = 0; i < count; i++)
1757ec681f3Smrg		stAttachmentMask |= 1 << statts[i];
1767ec681f3Smrg
1777ec681f3Smrg	newMask = stAttachmentMask & ~buffer->mask;
1787ec681f3Smrg
1797ec681f3Smrg	resized = (buffer->width != context->width)
1807ec681f3Smrg		|| (buffer->height != context->height);
1817ec681f3Smrg
1827ec681f3Smrg	if (resized || newMask) {
1837ec681f3Smrg		boolean ret;
1847ec681f3Smrg		TRACE("%s: resize event. old:  %d x %d; new: %d x %d\n", __func__,
1857ec681f3Smrg			buffer->width, buffer->height, context->width, context->height);
1867ec681f3Smrg
1877ec681f3Smrg		ret = hgl_st_framebuffer_validate_textures(stfbi,
1887ec681f3Smrg			context->width, context->height, stAttachmentMask);
1897ec681f3Smrg
1907ec681f3Smrg		if (!ret)
1917ec681f3Smrg			return ret;
1927ec681f3Smrg	}
1937ec681f3Smrg
1947ec681f3Smrg	for (i = 0; i < count; i++)
1957ec681f3Smrg		pipe_resource_reference(&out[i], buffer->textures[statts[i]]);
1967ec681f3Smrg
1977ec681f3Smrg	return true;
1987ec681f3Smrg}
1997ec681f3Smrg
2007ec681f3Smrg
2017ec681f3Smrgstatic int
2027ec681f3Smrghgl_st_manager_get_param(struct st_manager *smapi, enum st_manager_param param)
2037ec681f3Smrg{
2047ec681f3Smrg	CALLED();
2057ec681f3Smrg
2067ec681f3Smrg	switch (param) {
2077ec681f3Smrg		case ST_MANAGER_BROKEN_INVALIDATE:
2087ec681f3Smrg			return 1;
2097ec681f3Smrg	}
2107ec681f3Smrg
2117ec681f3Smrg	return 0;
2127ec681f3Smrg}
2137ec681f3Smrg
2147ec681f3Smrg
2157ec681f3Smrgstatic uint32_t hgl_fb_ID = 0;
2167ec681f3Smrg
2177ec681f3Smrg/**
2187ec681f3Smrg * Create new framebuffer
2197ec681f3Smrg */
2207ec681f3Smrgstruct hgl_buffer *
2217ec681f3Smrghgl_create_st_framebuffer(struct hgl_context* context, void *winsysContext)
2227ec681f3Smrg{
2237ec681f3Smrg	struct hgl_buffer *buffer;
2247ec681f3Smrg	CALLED();
2257ec681f3Smrg
2267ec681f3Smrg	// Our requires before creating a framebuffer
2277ec681f3Smrg	assert(context);
2287ec681f3Smrg	assert(context->display);
2297ec681f3Smrg	assert(context->stVisual);
2307ec681f3Smrg
2317ec681f3Smrg	buffer = CALLOC_STRUCT(hgl_buffer);
2327ec681f3Smrg	assert(buffer);
2337ec681f3Smrg
2347ec681f3Smrg	// calloc and configure our st_framebuffer interface
2357ec681f3Smrg	buffer->stfbi = CALLOC_STRUCT(st_framebuffer_iface);
2367ec681f3Smrg	assert(buffer->stfbi);
2377ec681f3Smrg
2387ec681f3Smrg	// Prepare our buffer
2397ec681f3Smrg	buffer->visual = context->stVisual;
2407ec681f3Smrg	buffer->screen = context->display->manager->screen;
2417ec681f3Smrg	buffer->winsysContext = winsysContext;
2427ec681f3Smrg
2437ec681f3Smrg	if (buffer->screen->get_param(buffer->screen, PIPE_CAP_NPOT_TEXTURES))
2447ec681f3Smrg		buffer->target = PIPE_TEXTURE_2D;
2457ec681f3Smrg	else
2467ec681f3Smrg		buffer->target = PIPE_TEXTURE_RECT;
2477ec681f3Smrg
2487ec681f3Smrg	// Prepare our frontend interface
2497ec681f3Smrg	buffer->stfbi->flush_front = hgl_st_framebuffer_flush_front;
2507ec681f3Smrg	buffer->stfbi->validate = hgl_st_framebuffer_validate;
2517ec681f3Smrg	buffer->stfbi->visual = context->stVisual;
2527ec681f3Smrg
2537ec681f3Smrg	p_atomic_set(&buffer->stfbi->stamp, 1);
2547ec681f3Smrg	buffer->stfbi->st_manager_private = (void*)buffer;
2557ec681f3Smrg	buffer->stfbi->ID = p_atomic_inc_return(&hgl_fb_ID);
2567ec681f3Smrg	buffer->stfbi->state_manager = context->display->manager;
2577ec681f3Smrg
2587ec681f3Smrg	return buffer;
2597ec681f3Smrg}
2607ec681f3Smrg
2617ec681f3Smrg
2627ec681f3Smrgvoid
2637ec681f3Smrghgl_destroy_st_framebuffer(struct hgl_buffer *buffer)
2647ec681f3Smrg{
2657ec681f3Smrg	CALLED();
2667ec681f3Smrg
2677ec681f3Smrg	int i;
2687ec681f3Smrg	for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
2697ec681f3Smrg		pipe_resource_reference(&buffer->textures[i], NULL);
2707ec681f3Smrg
2717ec681f3Smrg	FREE(buffer->stfbi);
2727ec681f3Smrg	FREE(buffer);
2737ec681f3Smrg}
2747ec681f3Smrg
2757ec681f3Smrg
2767ec681f3Smrgstruct st_api*
2777ec681f3Smrghgl_create_st_api()
2787ec681f3Smrg{
2797ec681f3Smrg	CALLED();
2807ec681f3Smrg	return st_gl_api_create();
2817ec681f3Smrg}
2827ec681f3Smrg
2837ec681f3Smrg
2847ec681f3Smrgstruct st_visual*
2857ec681f3Smrghgl_create_st_visual(ulong options)
2867ec681f3Smrg{
2877ec681f3Smrg	struct st_visual* visual;
2887ec681f3Smrg
2897ec681f3Smrg	CALLED();
2907ec681f3Smrg
2917ec681f3Smrg	visual = CALLOC_STRUCT(st_visual);
2927ec681f3Smrg	assert(visual);
2937ec681f3Smrg
2947ec681f3Smrg	// Determine color format
2957ec681f3Smrg	if ((options & BGL_INDEX) != 0) {
2967ec681f3Smrg		// Index color
2977ec681f3Smrg		visual->color_format = PIPE_FORMAT_B5G6R5_UNORM;
2987ec681f3Smrg		// TODO: Indexed color depth buffer?
2997ec681f3Smrg		visual->depth_stencil_format = PIPE_FORMAT_NONE;
3007ec681f3Smrg	} else {
3017ec681f3Smrg		// RGB color
3027ec681f3Smrg		visual->color_format = (options & BGL_ALPHA)
3037ec681f3Smrg			? PIPE_FORMAT_BGRA8888_UNORM : PIPE_FORMAT_BGRX8888_UNORM;
3047ec681f3Smrg		// TODO: Determine additional stencil formats
3057ec681f3Smrg		visual->depth_stencil_format = (options & BGL_DEPTH)
3067ec681f3Smrg			? PIPE_FORMAT_Z24_UNORM_S8_UINT : PIPE_FORMAT_NONE;
3077ec681f3Smrg    }
3087ec681f3Smrg
3097ec681f3Smrg	visual->accum_format = (options & BGL_ACCUM)
3107ec681f3Smrg		? PIPE_FORMAT_R16G16B16A16_SNORM : PIPE_FORMAT_NONE;
3117ec681f3Smrg
3127ec681f3Smrg	visual->buffer_mask |= ST_ATTACHMENT_FRONT_LEFT_MASK;
3137ec681f3Smrg
3147ec681f3Smrg	if ((options & BGL_DOUBLE) != 0) {
3157ec681f3Smrg		TRACE("double buffer enabled\n");
3167ec681f3Smrg		visual->buffer_mask |= ST_ATTACHMENT_BACK_LEFT_MASK;
3177ec681f3Smrg	}
3187ec681f3Smrg
3197ec681f3Smrg	#if 0
3207ec681f3Smrg	if ((options & BGL_STEREO) != 0) {
3217ec681f3Smrg		visual->buffer_mask |= ST_ATTACHMENT_FRONT_RIGHT_MASK;
3227ec681f3Smrg		if ((options & BGL_DOUBLE) != 0)
3237ec681f3Smrg			visual->buffer_mask |= ST_ATTACHMENT_BACK_RIGHT_MASK;
3247ec681f3Smrg    }
3257ec681f3Smrg	#endif
3267ec681f3Smrg
3277ec681f3Smrg	if ((options & BGL_DEPTH) || (options & BGL_STENCIL))
3287ec681f3Smrg		visual->buffer_mask |= ST_ATTACHMENT_DEPTH_STENCIL_MASK;
3297ec681f3Smrg
3307ec681f3Smrg	TRACE("%s: Visual color format: %s\n", __func__,
3317ec681f3Smrg		util_format_name(visual->color_format));
3327ec681f3Smrg
3337ec681f3Smrg	return visual;
3347ec681f3Smrg}
3357ec681f3Smrg
3367ec681f3Smrg
3377ec681f3Smrgvoid
3387ec681f3Smrghgl_destroy_st_visual(struct st_visual* visual)
3397ec681f3Smrg{
3407ec681f3Smrg	CALLED();
3417ec681f3Smrg
3427ec681f3Smrg	FREE(visual);
3437ec681f3Smrg}
3447ec681f3Smrg
3457ec681f3Smrg
3467ec681f3Smrgstruct hgl_display*
3477ec681f3Smrghgl_create_display(struct pipe_screen* screen)
3487ec681f3Smrg{
3497ec681f3Smrg	struct hgl_display* display;
3507ec681f3Smrg
3517ec681f3Smrg	display = CALLOC_STRUCT(hgl_display);
3527ec681f3Smrg	assert(display);
3537ec681f3Smrg	display->api = st_gl_api_create();
3547ec681f3Smrg	display->manager = CALLOC_STRUCT(st_manager);
3557ec681f3Smrg	assert(display->manager);
3567ec681f3Smrg	display->manager->screen = screen;
3577ec681f3Smrg	display->manager->get_param = hgl_st_manager_get_param;
3587ec681f3Smrg	// display->manager->st_manager_private is used by llvmpipe
3597ec681f3Smrg
3607ec681f3Smrg	return display;
3617ec681f3Smrg}
3627ec681f3Smrg
3637ec681f3Smrg
3647ec681f3Smrgvoid
3657ec681f3Smrghgl_destroy_display(struct hgl_display *display)
3667ec681f3Smrg{
3677ec681f3Smrg	if (display->manager->destroy)
3687ec681f3Smrg		display->manager->destroy(display->manager);
3697ec681f3Smrg	FREE(display->manager);
3707ec681f3Smrg	if (display->api->destroy)
3717ec681f3Smrg		display->api->destroy(display->api);
3727ec681f3Smrg	FREE(display);
3737ec681f3Smrg}
374