1/* 2 * Copyright 2012-2014, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Artur Wyszynski, harakash@gmail.com 7 * Alexander von Gluck IV, kallisti5@unixzen.com 8 */ 9 10#include "hgl_context.h" 11 12#include <stdio.h> 13 14#include "pipe/p_format.h" 15#include "util/u_atomic.h" 16#include "util/format/u_format.h" 17#include "util/u_memory.h" 18#include "util/u_inlines.h" 19#include "state_tracker/st_gl_api.h" /* for st_gl_api_create */ 20 21#include "GLView.h" 22 23 24#ifdef DEBUG 25# define TRACE(x...) printf("hgl:frontend: " x) 26# define CALLED() TRACE("CALLED: %s\n", __PRETTY_FUNCTION__) 27#else 28# define TRACE(x...) 29# define CALLED() 30#endif 31#define ERROR(x...) printf("hgl:frontend: " x) 32 33 34// Perform a safe void to hgl_context cast 35static inline struct hgl_context* 36hgl_st_context(struct st_context_iface *stctxi) 37{ 38 struct hgl_context* context; 39 assert(stctxi); 40 context = (struct hgl_context*)stctxi->st_manager_private; 41 assert(context); 42 return context; 43} 44 45 46// Perform a safe void to hgl_buffer cast 47//static inline struct hgl_buffer* 48struct hgl_buffer* 49hgl_st_framebuffer(struct st_framebuffer_iface *stfbi) 50{ 51 struct hgl_buffer* buffer; 52 assert(stfbi); 53 buffer = (struct hgl_buffer*)stfbi->st_manager_private; 54 assert(buffer); 55 return buffer; 56} 57 58 59static bool 60hgl_st_framebuffer_flush_front(struct st_context_iface* stctxi, 61 struct st_framebuffer_iface* stfbi, enum st_attachment_type statt) 62{ 63 CALLED(); 64 65 struct hgl_buffer* buffer = hgl_st_framebuffer(stfbi); 66 struct pipe_resource* ptex = buffer->textures[statt]; 67 68 if (statt != ST_ATTACHMENT_FRONT_LEFT) 69 return false; 70 71 if (!ptex) 72 return true; 73 74 // TODO: pipe_context here??? Might be needed for hw renderers 75 buffer->screen->flush_frontbuffer(buffer->screen, NULL, ptex, 0, 0, 76 buffer->winsysContext, NULL); 77 78 return true; 79} 80 81 82static bool 83hgl_st_framebuffer_validate_textures(struct st_framebuffer_iface *stfbi, 84 unsigned width, unsigned height, unsigned mask) 85{ 86 struct hgl_buffer* buffer; 87 enum st_attachment_type i; 88 struct pipe_resource templat; 89 90 CALLED(); 91 92 buffer = hgl_st_framebuffer(stfbi); 93 94 if (buffer->width != width || buffer->height != height) { 95 TRACE("validate_textures: size changed: %d, %d -> %d, %d\n", 96 buffer->width, buffer->height, width, height); 97 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) 98 pipe_resource_reference(&buffer->textures[i], NULL); 99 } 100 101 memset(&templat, 0, sizeof(templat)); 102 templat.target = buffer->target; 103 templat.width0 = width; 104 templat.height0 = height; 105 templat.depth0 = 1; 106 templat.array_size = 1; 107 templat.last_level = 0; 108 109 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) { 110 enum pipe_format format; 111 unsigned bind; 112 113 if (((1 << i) & buffer->visual->buffer_mask) && buffer->textures[i] == NULL) { 114 switch (i) { 115 case ST_ATTACHMENT_FRONT_LEFT: 116 case ST_ATTACHMENT_BACK_LEFT: 117 case ST_ATTACHMENT_FRONT_RIGHT: 118 case ST_ATTACHMENT_BACK_RIGHT: 119 format = buffer->visual->color_format; 120 bind = PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_RENDER_TARGET; 121 break; 122 case ST_ATTACHMENT_DEPTH_STENCIL: 123 format = buffer->visual->depth_stencil_format; 124 bind = PIPE_BIND_DEPTH_STENCIL; 125 break; 126 default: 127 format = PIPE_FORMAT_NONE; 128 bind = 0; 129 break; 130 } 131 132 if (format != PIPE_FORMAT_NONE) { 133 templat.format = format; 134 templat.bind = bind; 135 TRACE("resource_create(%d, %d, %d)\n", i, format, bind); 136 buffer->textures[i] = buffer->screen->resource_create(buffer->screen, 137 &templat); 138 if (!buffer->textures[i]) 139 return FALSE; 140 } 141 } 142 } 143 144 buffer->width = width; 145 buffer->height = height; 146 buffer->mask = mask; 147 148 return true; 149} 150 151 152/** 153 * Called by the st manager to validate the framebuffer (allocate 154 * its resources). 155 */ 156static bool 157hgl_st_framebuffer_validate(struct st_context_iface *stctxi, 158 struct st_framebuffer_iface *stfbi, const enum st_attachment_type *statts, 159 unsigned count, struct pipe_resource **out) 160{ 161 struct hgl_context* context; 162 struct hgl_buffer* buffer; 163 unsigned stAttachmentMask, newMask; 164 unsigned i; 165 bool resized; 166 167 CALLED(); 168 169 context = hgl_st_context(stctxi); 170 buffer = hgl_st_framebuffer(stfbi); 171 172 // Build mask of current attachments 173 stAttachmentMask = 0; 174 for (i = 0; i < count; i++) 175 stAttachmentMask |= 1 << statts[i]; 176 177 newMask = stAttachmentMask & ~buffer->mask; 178 179 resized = (buffer->width != context->width) 180 || (buffer->height != context->height); 181 182 if (resized || newMask) { 183 boolean ret; 184 TRACE("%s: resize event. old: %d x %d; new: %d x %d\n", __func__, 185 buffer->width, buffer->height, context->width, context->height); 186 187 ret = hgl_st_framebuffer_validate_textures(stfbi, 188 context->width, context->height, stAttachmentMask); 189 190 if (!ret) 191 return ret; 192 } 193 194 for (i = 0; i < count; i++) 195 pipe_resource_reference(&out[i], buffer->textures[statts[i]]); 196 197 return true; 198} 199 200 201static int 202hgl_st_manager_get_param(struct st_manager *smapi, enum st_manager_param param) 203{ 204 CALLED(); 205 206 switch (param) { 207 case ST_MANAGER_BROKEN_INVALIDATE: 208 return 1; 209 } 210 211 return 0; 212} 213 214 215static uint32_t hgl_fb_ID = 0; 216 217/** 218 * Create new framebuffer 219 */ 220struct hgl_buffer * 221hgl_create_st_framebuffer(struct hgl_context* context, void *winsysContext) 222{ 223 struct hgl_buffer *buffer; 224 CALLED(); 225 226 // Our requires before creating a framebuffer 227 assert(context); 228 assert(context->display); 229 assert(context->stVisual); 230 231 buffer = CALLOC_STRUCT(hgl_buffer); 232 assert(buffer); 233 234 // calloc and configure our st_framebuffer interface 235 buffer->stfbi = CALLOC_STRUCT(st_framebuffer_iface); 236 assert(buffer->stfbi); 237 238 // Prepare our buffer 239 buffer->visual = context->stVisual; 240 buffer->screen = context->display->manager->screen; 241 buffer->winsysContext = winsysContext; 242 243 if (buffer->screen->get_param(buffer->screen, PIPE_CAP_NPOT_TEXTURES)) 244 buffer->target = PIPE_TEXTURE_2D; 245 else 246 buffer->target = PIPE_TEXTURE_RECT; 247 248 // Prepare our frontend interface 249 buffer->stfbi->flush_front = hgl_st_framebuffer_flush_front; 250 buffer->stfbi->validate = hgl_st_framebuffer_validate; 251 buffer->stfbi->visual = context->stVisual; 252 253 p_atomic_set(&buffer->stfbi->stamp, 1); 254 buffer->stfbi->st_manager_private = (void*)buffer; 255 buffer->stfbi->ID = p_atomic_inc_return(&hgl_fb_ID); 256 buffer->stfbi->state_manager = context->display->manager; 257 258 return buffer; 259} 260 261 262void 263hgl_destroy_st_framebuffer(struct hgl_buffer *buffer) 264{ 265 CALLED(); 266 267 int i; 268 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) 269 pipe_resource_reference(&buffer->textures[i], NULL); 270 271 FREE(buffer->stfbi); 272 FREE(buffer); 273} 274 275 276struct st_api* 277hgl_create_st_api() 278{ 279 CALLED(); 280 return st_gl_api_create(); 281} 282 283 284struct st_visual* 285hgl_create_st_visual(ulong options) 286{ 287 struct st_visual* visual; 288 289 CALLED(); 290 291 visual = CALLOC_STRUCT(st_visual); 292 assert(visual); 293 294 // Determine color format 295 if ((options & BGL_INDEX) != 0) { 296 // Index color 297 visual->color_format = PIPE_FORMAT_B5G6R5_UNORM; 298 // TODO: Indexed color depth buffer? 299 visual->depth_stencil_format = PIPE_FORMAT_NONE; 300 } else { 301 // RGB color 302 visual->color_format = (options & BGL_ALPHA) 303 ? PIPE_FORMAT_BGRA8888_UNORM : PIPE_FORMAT_BGRX8888_UNORM; 304 // TODO: Determine additional stencil formats 305 visual->depth_stencil_format = (options & BGL_DEPTH) 306 ? PIPE_FORMAT_Z24_UNORM_S8_UINT : PIPE_FORMAT_NONE; 307 } 308 309 visual->accum_format = (options & BGL_ACCUM) 310 ? PIPE_FORMAT_R16G16B16A16_SNORM : PIPE_FORMAT_NONE; 311 312 visual->buffer_mask |= ST_ATTACHMENT_FRONT_LEFT_MASK; 313 314 if ((options & BGL_DOUBLE) != 0) { 315 TRACE("double buffer enabled\n"); 316 visual->buffer_mask |= ST_ATTACHMENT_BACK_LEFT_MASK; 317 } 318 319 #if 0 320 if ((options & BGL_STEREO) != 0) { 321 visual->buffer_mask |= ST_ATTACHMENT_FRONT_RIGHT_MASK; 322 if ((options & BGL_DOUBLE) != 0) 323 visual->buffer_mask |= ST_ATTACHMENT_BACK_RIGHT_MASK; 324 } 325 #endif 326 327 if ((options & BGL_DEPTH) || (options & BGL_STENCIL)) 328 visual->buffer_mask |= ST_ATTACHMENT_DEPTH_STENCIL_MASK; 329 330 TRACE("%s: Visual color format: %s\n", __func__, 331 util_format_name(visual->color_format)); 332 333 return visual; 334} 335 336 337void 338hgl_destroy_st_visual(struct st_visual* visual) 339{ 340 CALLED(); 341 342 FREE(visual); 343} 344 345 346struct hgl_display* 347hgl_create_display(struct pipe_screen* screen) 348{ 349 struct hgl_display* display; 350 351 display = CALLOC_STRUCT(hgl_display); 352 assert(display); 353 display->api = st_gl_api_create(); 354 display->manager = CALLOC_STRUCT(st_manager); 355 assert(display->manager); 356 display->manager->screen = screen; 357 display->manager->get_param = hgl_st_manager_get_param; 358 // display->manager->st_manager_private is used by llvmpipe 359 360 return display; 361} 362 363 364void 365hgl_destroy_display(struct hgl_display *display) 366{ 367 if (display->manager->destroy) 368 display->manager->destroy(display->manager); 369 FREE(display->manager); 370 if (display->api->destroy) 371 display->api->destroy(display->api); 372 FREE(display); 373} 374