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