| /* |
| * 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); |
| } |